I have my local nuget library repository separately both for my personal and work releted class libraries.
I have created some of the nuget packages for the libraries which are no longer in development. I did this only for them because I do not know how to update them automatically as soon as my project builds.
I have figured that all the work is being done by nuget command line with Visual Studio Command Prompt. So I can easily do the work I needed (of course I would know commands perfectly and I do not !)
Basically I want the following tasks to execute on the post-build event of my project.
On project build:
copying project dll into a specific folder (lib folder of the nuget package)
updating nuspec file for new file version (my project is increasing the file version on every build)
creating new nupkg file with new file version
Phil Haack shows some of this feature but it is still a prototype as far as I can tell.
So my requirement is the above. Has anyone else accomplished this?
The selected solution looks like it would work but it seems like there is a simpler solution for your requirements.
You can create a nuspec file that will read data from the project's metadata. You only need to do this once with this command:
C:\<Path to project>\nuget spec
This creates 'tokens' in the spec file that will will be replaced by the project's metadata when you create the nuget package. This includes the file version. You will want to replace and because all projects are technically suppose to have them.
More details can be found here: http://docs.nuget.org/docs/creating-packages/Creating-and-Publishing-a-Package#From_a_project
Then...
For .Net Framework (old-school) projects, in you project's Post build events you can do this:
nuget pack "$(ProjectPath)"
xcopy "$(TargetDir)*.nupkg" "<path where you are hosting your local nuget repo>" /C /Y
(assuming nuget.exe is available on your system PATH).
For .Net Core and Standard projects, nuget can't pack them (see https://github.com/NuGet/Home/issues/4491). Instead, use this as your post-build step:
dotnet pack "$(ProjectPath)" --no-build --include-source --include-symbols --output "<path where you are hosting your local nuget repo>"
Of course you can adjust the options to meet your needs. See https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-pack?tabs=netcore2x for dotnet pack command options.
Just in case someone else (like me) come across this ancient question - in the current era (VS2017, SDK/NugetReference format/ .NET Core / .NET Standard / Multi-target projects), where creation of NuGet package is an option in the Project Properties - so, only issue of local repository has to be solved:
If you have single-target project, to copy your .nupkg file to local NuGet repository, add Post-build event (Project properties > Build Events > Post-build event command line):
xcopy $(TargetDir)*.nupkg [path to your local nuget repository] /s
Like:
xcopy $(TargetDir)*.nupkg G:\imbVelesOpenSource\LocalNuGet\imbVelesSecondGeneration\ /s
If you have multi-target project, to copy your .nupkg file to local NuGet repository:
add Post-build event (Project properties > Build Events > Post-build event command line):
xcopy $(TargetDir)..*.nupkg [path to your local nuget repository] /s
Like:
xcopy $(TargetDir)..*.nupkg G:\imbVelesOpenSource\LocalNuGet\imbVelesSecondGeneration\ /s
Update:
Forget post-build events, there is a cleaner way (xcopy approach works strange for multi-target projects), just add this in project XML:
<Target Name="CopyPackage" AfterTargets="Pack">
<Copy SourceFiles="$(OutputPath)$(PackageId).$(PackageVersion).nupkg" DestinationFolder="G:\imbVelesOpenSource\LocalNuGet\imbVelesSecondGeneration\" />
</Target>
Update
For newer NuGet versions, which cut off the last 0 (patch from a 0.0.0.0 version notation), you will need to regex the PackageVersion:
<Target Name="CopyPackage" AfterTargets="Pack">
<Copy SourceFiles="$(OutputPath)$(PackageId).$([System.Text.RegularExpressions.Regex]::Replace("$(PackageVersion)", "^(.+?)(\.0+)$", "$1")).nupkg" DestinationFolder="G:\imbVelesOpenSource\LocalNuGet\imbVelesSecondGeneration\" />
</Target>
Jeremy Skinner has written a blog post on how he performs automated builds of packages and uploads them to the NuGet Gallery. I think that it matches your requirements.
Basically he uses MsBuild to apply the version (with the MsBuild Community Extensions UpdateXml task) to the nuspec file and invoke the nuget.exe to package it up.
I recently published a solution for this that actually creates/updates the nuspec files during the build, so don't have to do so manually, then creates the nupkg files.
All you will have to add is a post-build event for copying the packages to their destination (or add it as an optional stage to my solution).
You can find an article with a walk-through guide here and the source code + binary here.
With the latest nuget package format using "PackageReference" tags you can use the following simple postbuild event in your csproj to update nuspec file with latest dependencies.
<Target Name="AfterBuild">
<WriteLinesToFile File="dependencies.xml" Overwrite="true" Lines=""/>
<WriteLinesToFile File="dependencies.xml" Overwrite="false" Lines="<dependencies>"/>
<WriteLinesToFile File="dependencies.xml" Overwrite="false" Lines="<dependency id="%(PackageReference.Identity)" version="%(PackageReference.Version)" />" />
<WriteLinesToFile File="dependencies.xml" Overwrite="false" Lines="</dependencies >"/>
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted -command "$xml = [xml] (Get-Content Project.nuspec); $xml.package.metadata.RemoveChild($xml.package.metadata.dependencies); $dependencies = [xml](Get-Content dependencies.xml); $xml.Package.Metadata.AppendChild($xml.ImportNode($dependencies.Dependencies, $true)); $xml.Save('Project.nuspec')""/>
<Delete Files="dependencies.xml" />
</Target>
Only premise for this is that you have a nuspec file with rest of the metadata mentioned in the project directory. Here is a sample nuspec file:
<?xml version="1.0"?>
<package>
<metadata>
<id>Package Id</id>
<version>1.0.0</version>
<authors>Author name</authors>
<owners>Owner name</owners>
<description>Description</description>
<contentFiles>
<files include="**/content.zip" buildAction="None" copyToOutput="true" flatten="false" />
</contentFiles>
<dependencies>
</dependencies>
</metadata>
<files>
<file src="bin\Release\Project.dll" target="lib\net462" />
<file src="bin\Release\Project.pdb" target="lib\net462" />
<file src="bin\Release\file.zip" target="Content" />
</files>
</package>
I solved it by using a command line
Let's assume you have added the location of NuGet to your path environment or copies a stable version to a given directory (this is what I did)
I have my NuGet.exe as well as my certificate in a folder named D:\Build, you may need to update this to fit your path.
Then let's assume you have a codesign certificate file named: "CodeSignCertificate.pfx"
with a password: pa$$w0rd
You can get a simple codesign certificate for 17 euro from Ascertia. they also have free trial certificates that are valid for 10 days. the link https://account.ascertia.com/onlineCA/default
then as a one liner I use :
for %f in (X:\Packages\*.nupkg) do D:\Build\nuget sign %f -CertificatePath D:\Build\CodeSignCertificate.pfx -Timestamper http://timestamp.digicert.com -CertificatePassword pa$$w0rd
This sign all my packages in my output directory
if you only want to sign the lastest the NuGet package as this might be the one you just compiled then you can use something like this.
set Path="X:\ASP-WAF\DLL"
for /f "tokens=*" %%a in ('dir /A:-D /B /O:-D /S %Path%') do set NEW=%%a&& goto:n
:n
sign %NEW% -CertificatePath D:\Build\CodeSignCertificate.pfx -Timestamper http://timestamp.digicert.com -CertificatePassword pa$$w0rd
it's not a one-line but you can put it in a bat file and call that in your post build.
Related
On Ubuntu I'd like to wrap a few C# DLL files into a NuGet package. On Windows one would use the NuGet package explorer or nuget.exe + manually edited *.csproj.nuspec. In summary when manually editing the *.nuspec file one may add DLLs via the <files> section:
<files>
<file src="some\Path\YourDll.dll" target="lib"></file>
</files>
On Ubuntu I'd like to use dotnet pack instead. However it seems like it's not able to operate on a *.csproj.nuspec file:
Usage: dotnet pack [options] <PROJECT | SOLUTION>
Arguments:
<PROJECT | SOLUTION> The project or solution file to operate on. If a file is not specified, the command will search the current directory for one.
Options:
-h, --help Show command line help.
-o, --output <OUTPUT_DIR> The output directory to place built packages in.
--no-build Do not build the project before packing. Implies --no-restore.
--include-symbols Include packages with symbols in addition to regular packages in output directory.
--include-source Include PDBs and source files. Source files go into the 'src' folder in the resulting nuget package.
-c, --configuration <CONFIGURATION> The configuration to use for building the package. The default for most projects is 'Debug'.
--version-suffix <VERSION_SUFFIX> Set the value of the $(VersionSuffix) property to use when building the project.
-s, --serviceable Set the serviceable flag in the package. See https://aka.ms/nupkgservicing for more information.
--nologo Do not display the startup banner or the copyright message.
--interactive Allows the command to stop and wait for user input or action (for example to complete authentication).
--no-restore Do not restore the project before building.
-v, --verbosity <LEVEL> Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].
--runtime <RUNTIME_IDENTIFIER> The target runtime to restore packages for.
--no-dependencies Do not restore project-to-project references and only restore the specified project.
--force Force all dependencies to be resolved even if the last restore was successful.
This is equivalent to deleting project.assets.json.
Can I wrap C# DLLs into a NuGet package on Ubuntu using the dotnet CLI? Or do I have to use the nuget CLI (apt-get install nuget) instead with the approach like on Windows?
I would add this into the .csproj file:
<ItemGroup>
<Content Include="some.dll" PackageCopyToOutput="true">
<pack>true</pack>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
It's not pretty but it works.
How do you copy a text file that has been included along with the DLLs within a NuGet package?
When I use my custom NuGet package in another solution (c:\dev\ for this example), the resulting file structure within c:\dev\package\projectId\lib\netstandard2.0\ has many DLLs and a text file, say file.txt. The DLLs are all copied upon building the solution, but the text file is left behind.
Within the .nuspec file, I originally included the file under <files><file src="foo\file.txt" target="lib\netstandard2.0"/></files>. The file.txt ends up in the packages folder when the NuGet package is restored, but it's not copied into the build directory.
Attempt 1: I tried using the contentFiles property within the nuspec file, since the nuspec reference points there a few times. I got nuget.exe pack command to work with this new property (i.e. no syntax errors), but there was no change in how the content (file.txt) was handled.
Attempt 2: I tried using a projectId.targets file. This uses a Target that has an ItemGroup that includes the file. Then, I tried using a Copy event, pointing to the destination folder as $(OutputPath).
It seems awfully hard to copy a file that is included in the package to the build directory, having to dive into MSBuild events and the like.
I'm at a loss here, and any pointers would be welcome.
Edits # 1:
I tried adding this section to the metadata, per a suggestion below:
<contentFiles>
<files include="any\any\file.txt" buildAction="EmbeddedResource" />
</contentFiles>
This works in a small test case. The file.txt shows up nicely in both Visual Studio and in the build directory. Weirdly, it doesn't work in my main project using the same exact syntax (I'm using .NET Core 2.0 in both). Also, in NuGet Package Explorer, it shows up in the package contents when it's alone. But when I add something under <files><file src="lib\netstandard2.0\test.dll" target="lib\netstandard2.0"/></files>, it disappears from that view.
Edits # 2:
I think there's something else going on... Here is the .nuspec file from our main project. When I add a content file with the working suggestions below, it still doesn't show up (for either .NET Core 2.0 or .NET Framework 4.7.1). Is the .targets file messing this up somehow?
How to copy a text file from NuGet package during build of C# code that uses the package?
You should use contentFiles property and set copyToOutput="true" for the text file file.txt.
My test .nuspec file:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MyTestCore</id>
<version>5.0.0</version>
<authors>TestContentFile</authors>
<owners>TestContentFile</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Package Description</description>
<contentFiles>
<files include="any/any/file.txt" buildAction="content" flatten="true" copyToOutput="true"/>
</contentFiles>
</metadata>
<files>
<file src="contentFiles/any/any/file.txt" target="contentFiles/any/any" />
</files>
</package>
After pack this .nuspec file, then add the nuget package to the project, build the project, the text file will copy to the build directory:
Check the update answer for the similar issue for some more details.
You have to define build action to the file.
<contentFiles>
<!-- Include Assets as Content -->
<files include="foo\file.txt" buildAction="EmbeddedResource" />
</contentFiles>
I have created a Nuget package using Nuget Package Explorer. The package has some third party dlls that I use in my code. I dlls are included in the Nuget package and not referenced directly in the project references. The Nuget Package has the following.
- thirdPartyAAA.dll
- thirdPartyAAA.xml (Needed by thirdPartyAAA.dll)
- thirdPartyBBB.dll (needed by thirdPartyAAA.dll
- thirdPartyBBB.dll.config (used by thirdPartyBBB.dll)
- Dependency on HtmlAgilityPack nuget (Needed by thirdPartyAAA.dll)
- Dependency om RestSharp nuget (Needed by thirdPartyAAA.dll)
The problem is: when I reference this Nuget package in the code and compile the code I only get aaa.dll in the bin output folder. the following files are missing from the bin folder:
- thirdPartyAAA.xml
- thirdPartyBBB.dll
- thirdPartyBBB.dll.config
- All dlls from HtmlAgilityPack nuget
- All dll from RestSharp nuget
In my code I directly reference thirdPartyAAA.dll.
Is there a way - either during creating the Nuget Package or when referencing the package - to force the Nuget Package to restore all its contents and its dependencies? I need all the files that's included in the Nuget Package to be restored regardless if they are directly references in the code or not.
thank you all for your help.
Here is the manifest of the package if it helps.
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MyPackage</id>
<version>1.0.0</version>
<title></title>
<authors>Dev</authors>
<owners>Dev</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>My package description.</description>
<dependencies>
<dependency id="HtmlAgilityPack" version="1.4.9" />
<dependency id="RestSharp" version="105.0.1" />
</dependencies>
</metadata>
<files>
<file src="content\thirdPartyAAA.chm" target="content\thirdPartyAAA.chm" />
<file src="content\thirdPartyAAA.XML" target="content\thirdPartyAAA.XML" />
<file src="content\thirdPartyBBB.dll.config" target="content\thirdPartyBBB.dll.config" />
<file src="lib\thirdPartyAAA.dll" target="lib\thirdPartyAAA.dll" />
<file src="lib\thirdPartyBBB.dll" target="lib\thirdPartyBBB.dll" />
</files>
</package>
The problem is: when I reference this Nuget package in the code and compile the code I only get aaa.dll in the bin output folder. the following files are missing from the bin folder:
- thirdPartyAAA.xml
- thirdPartyBBB.dll
- thirdPartyBBB.dll.config
- All dlls from HtmlAgilityPack nuget
- All dll from RestSharp nuget
First, for the thirdPartyBBB.dll, you should make sure the target framework version of project is higher than your dll's target framework. For example, If the target framework version of your project is .net 4.6.2, the target framework version of your thirdPartyBBB.dll should be lower than .net 4.6.2. Otherwise, you are referring a dll file with higher version target framework to the project with lower version target framework. This is incompatible.
Besides, for the dependencies of this package, you can check if those dependencies added to the project, and the properties Copy Local of those dlls are set to True. It works fine on my side.
Second, for the content file, you should add a .targets file in the build folder in your package with following code to copy those content files to the bin folder:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="$(ProjectDir)thirdPartyAAA.chm">
<Link>thirdPartyAAA.chm</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CustomToolNamespace></CustomToolNamespace>
</None>
<None Include="$(ProjectDir)thirdPartyAAA.XML">
<Link>thirdPartyAAA.XML</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CustomToolNamespace></CustomToolNamespace>
</None>
<None Include="$(ProjectDir)thirdPartyBBB.dll.config">
<Link>thirdPartyBBB.dll.config</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CustomToolNamespace></CustomToolNamespace>
</None>
</ItemGroup>
</Project>
For some details info, please check this thread.
Alternatively, you can use Install.ps1 file to change the property, the script looks like:
param($installPath, $toolsPath, $package, $project)
function MarkDirectoryAsCopyToOutputRecursive($item)
{
$item.ProjectItems | ForEach-Object { MarkFileASCopyToOutputDirectory($_) }
}
function MarkFileASCopyToOutputDirectory($item)
{
Try
{
Write-Host Try set $item.Name
$item.Properties.Item("CopyToOutputDirectory").Value = 2
}
Catch
{
Write-Host RecurseOn $item.Name
MarkDirectoryAsCopyToOutputRecursive($item)
}
}
#Now mark everything in the a directory as "Copy to newer"
MarkDirectoryAsCopyToOutputRecursive($project.ProjectItems.Item("TheFolderOfYourContentFiles"))
You can check similar issue for details.
In addition, I have created a test nuget package, you can check if it works for you, test it with .net framework project with target framework 4.6 and above.
https://1drv.ms/u/s!Ai1sp_yvodHf1QJriMiGQWdYveRm
Hope this helps.
Go to your solution explorer ,
on Ur project references,
right click on the DLL which is missing from the bin folder. Select properties, then make "copy local " to true. This will copy the DLL to the build path after compiling.
Go to your solution explorer ,
on Ur project references,
right click on the DLL which is missing from the bin folder. Select properties, then make "copy local " to true. This will copy the DLL to the build path after compiling.
For nuget restoring please refer the below link
https://learn.microsoft.com/en-us/nuget/consume-packages/package-restore-troubleshooting
I recently ran into almost exactly the same problem.
After 2 days, I discovered several posts that clarified that the contents folder are ONLY deployed during the +initial+ installation of the nuget.
What this means is that any files deployed as CONTENT are intended to be checked into your version control system, just like any other code in your project.
They are specifically NOT deployed when VS runs a "package restore" as it does when you build a project and some packages are missing.
I have a custom made command line tool, which performs some code generation operations. Basically, it takes one assembly as input and, through reflection, searches for certaing custom attributes, used to trigger generation of external (JavaScript) files.
Everything works (almost) fine, but the distribution and execution of the tool is somewhat disorganized. I would like to pack it as a Nuget package (hosted in a private repository), which would essentially contain the tool and a build target that should trigger the execution of the tool.
How should I package the tool? I read about the special Nuget tool, content, and build folders, and I don't know where to put what, and how to setup a custom target.
I don't know if the question is "too broad", but even if I know pretty exactly what I need, I'm in kind of a blank page syndrome.
I would put the tool into the build directory inside the NuGet package and then have a custom MSBuild .targets file in the same build directory. This MSBuild .targets file would then be written in such a way so it is called at some point during the build process.
\build
\MyPackage.targets
Then your build targets file would insert itself into the build process:
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
MyCustomTarget
</BuildDependsOn>
</PropertyGroup>
<Target Name=“MyCustomTarget“>
<!-- Execute tool -->
</Target>
The above should run the MyCustomTarget as the last item during the build.
In post build action specify $(SolutionDir).nuget\nuget.exe pack $(ProjectPath) -IncludeReferencedProjects.
Also you can specify nuspec file. As described here https://docs.nuget.org/create/nuspec-reference.
Example:
<?xml version="1.0"?>
<package >
<metadata>
<id>SDK</id>
<version>$version$</version>
<title>$title$</title>
<authors>$author$</authors>
<owners>$author$</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description>
<releaseNotes>Initial release</releaseNotes>
<copyright>Copyright 2016</copyright>
<tags>SDK</tags>
</metadata>
<files>
<file src="tools\install.ps1" target="tools\install.ps1" />
</files>
</package>
Code:
if $(ConfigurationName) == Release (
cd $(ProjectDir)
nuget spec Entities -f
nuget pack DeusPak.Entities.csproj -Prop Configuration=Release
nuget push DeusPak.Entities.$(version).nupkg $(MYGET_API_KEY) -Source http://www.myget.org/F/lojaali/api/v2/package
)
I have just started to play around with NuGet and want to know how to include the version number in my NuGet package. I am currently hard coding it into the post-build event which is obviously not what I want to keep doing. Can anybody help?
This is my current post-build event :
if $(ConfigurationName) == Release (
cd $(ProjectDir)
nuget spec Dev-f
nuget pack Dev.csproj -Prop Configuration=Release
nuget push Dev.1.0.0.0.nupkg $(MYGET_API_KEY) -Source http://www.myget.org/F/api/v2/package
)
Update:
OK, I have managed to build the DLL with the correct auto incremented version number :
if $(ConfigurationName) == Release (
cd $(ProjectDir)
nuget spec Dev -f
nuget pack Dev.csproj -Prop Configuration=Release
nuget push Dev.$(version).nupkg $(MYGET_API_KEY) -Source http://www.myget.org/F/api/v2/package
)
But this version does not show on my list of MyGet packages. How do I get it to show there so it can be downloaded? Or can this only be done manually by clicking 'Add a package'?
Just extending a bit the solution provided by Carlos J López, i used the AfterBuild script to actually call NuGet and provide the version parameter.
In my case, I also added "cd $(ProjectDir)" to the post build event, which actually happens before the AfterBuild script.
Cheers,
<Target Name="AfterBuild" Condition="'$(Configuration)' == 'Release'">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="AssemblyVersion" />
</GetAssemblyIdentity>
<Exec Command="$(SolutionDir)\.nuget\nuget pack $(ProjectName).nuspec -Version %(AssemblyVersion.Version)" />
<Message Text="$(SolutionDir)\.nuget\nuget pack $(ProjectName).nuspec -Version %(AssemblyVersion.Version)" Importance="high" />
</Target>
It is not clear in your question, but assuming you want to sync the version of your package with the version of your assembly, you can simply manage the AssemblyVersion attribute in the project's AssemblyInfo.cs file.
[assembly: AssemblyVersion("1.0.0")]
or if you want to use auto-generated build numbers
[assembly: AssemblyVersion("1.0.0.*")]
If you want to deviate from the assembly's version, and only specify the package version, you can use the AssemblyInformationalVersion attribute in the AssemblyInfo.cs file.
[assembly: AssemblyInformationalVersion("1.0.0")]
It's also not clear from the question what versioning strategy you use, but I'll assume you want to apply Semantic Versioning (where the first 3 version numbers are most relevant). In general when auto-creating NuGet packages, I'd recommend you to create a tokenized nuspec file in your csproj directory, so you can more easily manipulate the package metadata. FYI, there's even a NuGet package to assist you with that:
Install-Package NuSpec
NuGet will look for this nuspec (make sure it's called MyProject.nuspec) when targeting MyProject.csproj.
<package>
<version>$version$</version>
...
</package>
I also explained this on the MyGet blog in this post: http://blog.myget.org/post/2012/04/27/NuGet-version-token-explained.aspx
A post build that calls nuget pack should be good enough then, assuming you simply change the assembly version before building.
nuget pack MyProject.csproj
This is how you can get a $(version) variable in your after build event, which should be as good as post build.
<Target Name="AfterBuild" Condition="'$(Configuration)' == 'Release'">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="AssemblyVersion" />
</GetAssemblyIdentity>
<Exec Command="echo %(AssemblyVersion.Version)" />
<Message Text="Released %(AssemblyVersion.Version)" Importance="high" />
</Target>
So you would have to modify your .csproj file since VS does not provide an UI for that.