Nuget pack myproject.csproj major shortcomings

May 9, 2011 at 9:10 PM
Edited May 9, 2011 at 9:11 PM

After discussing on this topic back and forth with @davidebbo I've come to understand why I've been so put aback by this feature as it stands right now. My understanding of this feature is that it was created to facilitate easier configuration for simple scenarios. That by pulling information from the assemblyinfo you can bypass the need of having to fill in the nuspec file by hand.

This feature works rather well on it's own. It however starts to break down past just about anything but demonstration purposes.

First, it can't be used in any type of automation sense. Since this will cause the package to rebuild you can't use this in a build process.  Since it bundles up your DLL into the package, I don't think there's any way to have it add powershell files or transforms or anything else you need (or is there?) so at this point you'd either want to manually add those files using the package explorer. That is not a very repeatable process.

At this point, my thoughts were well, it has the nuspec file I just need to pull that file out and use that in my project. Except that nuspec file has only parts of the information, like the description and version numbers.

So as it stands, it seems like this feature is entirely unusable: you can't use it in a build script, you can't readily use the files it produces for reverse engineering your own package, and it's not robust enough to create working packages for all but demonstrative scenarios.

May 9, 2011 at 9:17 PM

Note that when you use this feature, you can also have a nuspec file (run 'nuget spec' to create it). It is in fact the recommended thing to do. Once you have a nuspec file, you can easily add arbitrary files to your package using the <files> section (see doc). So the purpose of this feature is not really to bypass the need for a nuspec file, but instead to not have to manually specify a bunch of things that can be infer from the project.

I agree that the fact that it builds the project is quirky, and we should probably move away from that.

May 9, 2011 at 9:28 PM
Edited May 9, 2011 at 9:30 PM
davidebbo wrote:

 Once you have a nuspec file, you can easily add arbitrary files to your package using the <files> section (see doc). So the purpose of this feature is not really to bypass the need for a nuspec file, but instead to not have to manually specify a bunch of things that can be infer from the project.

Why doesn't it complete the files section, when instead it uses some other setup to arrange files?

May 9, 2011 at 9:31 PM

Not sure I understand your question. What do you mean by "some other setup"?

May 10, 2011 at 2:11 PM

Having been doing some more thought on this question. I believe where the disconnect comes from how good nuget pack in isolation is at building what I would want for the majority of my nuget usage. (single DLL being packaged up).

Since nuget directly builds your project, it knows to use the bin directory output as the input target of the nuget package creation. Which then just grabs every file in the bin dir and puts it in the lib folder due to the default handling of nuget.

Going back to my other post, if you pull the created config out of package and then run nuget against that nuspec in the project root you end with all of the files in the folder being added.

I think what would really improve the value of pack would be for it to generate the completed package AND an external nuspec file. This file would then be in the same folder as the csproj so you could have nuget build out the <files> section in relation to the project root to the files in the bin folder. This would also give people a much better tool on understanding the configuration of nuget since that nuspec would have the most common elements in it, it would also be a good target to load with comment hints on how to add in the transformations / power shell scripts, along with tips on how to integrate the package build into a post build event. This would make the files akin to the web.config files that when you start new projects come with pretty helpful documentation in them.

This would greatly improve the ability to get working with Nuget, right now there still feels like alot of hoops to jump through to get nuget as part of your workflow.

May 10, 2011 at 2:16 PM

Further thoughts to really improve this feature, to make the packing process able to defer to the assembly info for the version # information if the nuspec file is blank on it. If it can't load it from the assemblyinfo at that point nuget can error or whatever it would do currently.

Having to maintain the same information in both Nuspec and assemblyinfo seems tedious. It would be great if you could use nuspec just to add the extra information and that the core of the nuget gallery information would be scrapped from the assembly info. (unless people want to do it all manually then by all means)

May 10, 2011 at 2:58 PM
UppercuT does what you are looking for with updating both nuspec and the assembly files: http://devlicio.us/blogs/rob_reynolds/archive/2011/01/23/uppercut-v1-2-nuget-support.aspx
Coordinator
May 10, 2011 at 4:36 PM

Actually, that feature is already baked in. If you run:

Nuget Spec MyProject.csproj

It generates a spec file with placeholders.

<?xml version="1.0"?>

<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">

<metadata>

<id>$id$</id>

<version>$version$</version>

<authors>$author$</authors>

<owners>$author$</owners>

<licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>

<projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>

<iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>

<requireLicenseAcceptance>false</requireLicenseAcceptance>

<description>$description$</description>

<tags>Tag1 Tag2</tags>

</metadata>

</package>

Every time you run:

NuGet Pack MyProject.csproj

It merges the values from the AssemblyInfo into the NuSpec. So you can modify this NuSpec with <files> etc, but still have the assembly version merged in.

May 10, 2011 at 4:46 PM
Haacked wrote:

Actually, that feature is already baked in. If you run:

 

Nuget Spec MyProject.csproj

 

It generates a spec file with placeholders.

 

<?xml version="1.0"?>

<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">

<metadata>

<id>$id$</id>

<version>$version$</version>

<authors>$author$</authors>

<owners>$author$</owners>

Is there documentation on this somewhere? Or what do those values map to because putting them back in the first pack attempt with them "The replacement token 'id' has no value."

Coordinator
May 10, 2011 at 4:50 PM

We’re a little behind in our docs on this feature. It’s brand new. We’re always looking for volunteers to help us with docs.

As for the mapping, I believe:

· Id maps to [assembly: AssemblyTitle("ID.Goes.Here")]

· Version maps to [assembly: AssemblyVersion("1.0.0.0")]

· Author maps to [assembly: AssemblyCompany("Microsoft")]

· Description maps to [assembly: AssemblyDescription("")]

May 10, 2011 at 5:05 PM
I think Id maps to assembly name, and Title maps to AssemblyTitleAtribute value.

Sent from either Windows Phone or iPhone. You don't know.

From: Haacked
Sent: Tuesday, May 10, 2011 8:51 AM
To: Luan Nguyen
Subject: Re: Nuget pack myproject.csproj major shortcomings [nuget:256959]

From: Haacked

We’re a little behind in our docs on this feature. It’s brand new. We’re always looking for volunteers to help us with docs.

As for the mapping, I believe:

· Id maps to [assembly: AssemblyTitle("ID.Goes.Here")]

· Version maps to [assembly: AssemblyVersion("1.0.0.0")]

· Author maps to [assembly: AssemblyCompany("Microsoft")]

· Description maps to [assembly: AssemblyDescription("")]

Coordinator
May 10, 2011 at 5:08 PM

Ah yeah, my mistake.

May 10, 2011 at 5:15 PM

What does id map to? Because I'm not seeing anything like  [assembly: AssemblyNameAttribute("")], the project properties are definitely configured to use an assembly name and trying to pack gives me the "The replacement token 'id' has no value."

Coordinator
May 10, 2011 at 5:17 PM

Does your assembly have that attribute applied? It needs to not be blank.

Add this to your AssemblyInfo.cs file (typically in the Properties folder)

[assembly: AssemblyNameAttribute("MyPackageId")]

May 10, 2011 at 5:27 PM
Haacked wrote:

Does your assembly have that attribute applied? It needs to not be blank.

 

Add this to your AssemblyInfo.cs file (typically in the Properties folder)

 

[assembly: AssemblyNameAttribute("MyPackageId")] 

 

Resharper and visual studio tell me that class does not exist.

Coordinator
May 10, 2011 at 5:33 PM

Doh! I should try things out before I reply. Sorry L


It’s the actual assembly name that should fill that in. You’re right, there is no attribute.

May 10, 2011 at 5:35 PM
Haacked wrote:

Doh! I should try things out before I reply. Sorry L


It’s the actual assembly name that should fill that in. You’re right, there is no attribute.

Sounds like a bug then, i'll open an issue on this

Coordinator
May 10, 2011 at 5:36 PM

Please attach a repro project to your bug.

May 10, 2011 at 5:38 PM
Haacked wrote:

Does your assembly have that attribute applied? It needs to not be blank.

 

Add this to your AssemblyInfo.cs file (typically in the Properties folder)

 

[assembly: AssemblyNameAttribute("MyPackageId")] 

 

Does this only work for projects that you build with the pack my.csproj and not for pack my.nuspec?

Coordinator
May 10, 2011 at 5:41 PM

Yeah, you have to run:

NuGet Pack MyProject.csproj

And we merge those values into the nuspec file as long as you have one.

One thing we should consider, and perhaps log this as a feature suggestion, is if we detect a csproj with the same name as the nuspec in the same directory, we should go ahead and do the merge. This would be a useful convention.

For example, suppose you did this:

NuGet Spec MyProject.csproj

That creates a MyProject.nuspec file in the same directory as the .csproj file. If you then run

NuGet Pack MyProject.nuspec

We should look for a MyProject.csproj in the same directory and if it’s there, use it to fill in the replacement tokens.

Likewise, we could consider allowing you to specify the project.

NuGet Pack MyProject.nuspec –Project ..\..\MyProject.csproj

Thoughts?

May 10, 2011 at 5:41 PM

You need to run 'nuget pack' on the csproj, not the nuspec. But it will pick up the nuspec. Sorry for the poor doc.

But docs and minor quirkes aside, I think this is a solid workflow, and is more flexible than your suggestion to have nuget generate a one-time nuspec file from the project's content as you suggest above. That just would not work well when your project changes (e.g. you add a content file to it).

May 10, 2011 at 5:44 PM
Haacked wrote:

One thing we should consider, and perhaps log this as a feature suggestion, is if we detect a csproj with the same name as the nuspec in the same directory, we should go ahead and do the merge. This would be a useful convention.

 

We chose not to do that for fear of causing a breaking change with existing scenarios where users have the nuspec and csproj together but don't expect that. However, if we think the breaking change risk is low enough, we can still consider it.

Coordinator
May 10, 2011 at 5:59 PM

How would it be a breaking change? Existing NuSpec files wouldn’t have those replacement tokens, right? We could make it so that it only looks for a project file *if* it has replacement tokens.

May 10, 2011 at 6:09 PM

It's not about the replacement tokens, but about the extra content files that are brought in based on the project file, which would not have happened before.

May 10, 2011 at 6:41 PM
davidebbo wrote:

You need to run 'nuget pack' on the csproj, not the nuspec. But it will pick up the nuspec. Sorry for the poor doc.

But docs and minor quirkes aside, I think this is a solid workflow, and is more flexible than your suggestion to have nuget generate a one-time nuspec file from the project's content as you suggest above. That just would not work well when your project changes (e.g. you add a content file to it).

 

> nuget help pack
usage: NuGet pack <manifest> [options]

Creates a NuGet package based on the specified nuspec or project file.

fyi


Honestly at this point I'm even more confused than when I started on what I should do to integrate with nuget best.

What I certainly have seen:

  • nuspec files are likely to be build specific  (debug vs release due to bin folder locations)
  • nuget pack my.csproj is not able to be used as a post build action for the fact it builds the project itself

I'm not really seeing any ability to create a workflow around this atleast inside of visual studio. The most of a workflow I could see from this is creating a bat file during the post build process which allows you to just call it nuget with the right arguments, this isn't terrible but the funny thing is that the bat file will mutate itself since calling pack will then build the project again this time without a solution.

I'm perplexed at this point at even how to handle the difference between debug & release having different locations. I don't even see an argument for supplying the nuspec filename or csproj filename to pass in X.Release.nuspec

May 10, 2011 at 7:00 PM

The fact that is builds the project is something we need to fix (http://nuget.codeplex.com/workitem/1036). Once we get passed that, you'll be able to add it as a post build action.

As for debug vs retail, you can choose that by adding '/conf debug' or '/conf release' to the 'nuget pack' line.

May 10, 2011 at 10:17 PM
davidebbo wrote:

The fact that is builds the project is something we need to fix (http://nuget.codeplex.com/workitem/1036). Once we get passed that, you'll be able to add it as a post build action.

As for debug vs retail, you can choose that by adding '/conf debug' or '/conf release' to the 'nuget pack' line.

What about the files list? They're configuration dependent. Maybe files should have like a target attribute?

<files configuration="Release">
    <file src="bin\Release\System.ExtensionMethod.dll" />
    <file src="bin\Release\System.ExtensionMethod.pdb" />
  </files>

<files configuration="Debug">
    <file src="bin\Debug\System.ExtensionMethod.dll" />
    <file src="bin\Debug\System.ExtensionMethod.pdb" />
  </files>

May 10, 2011 at 10:19 PM

The advantage of running nuget pack on a project file is that the relevant binaries are automatically included, so this is not necessary. In your scenario, is System.ExtensionMethod.dll what your project is building, or is it some other assembly that it's using?

May 10, 2011 at 11:21 PM
davidebbo wrote:

The advantage of running nuget pack on a project file is that the relevant binaries are automatically included, so this is not necessary. In your scenario, is System.ExtensionMethod.dll what your project is building, or is it some other assembly that it's using?

And I guess this brings us full circle. Working with this api is extremely confusing, I think there's way too much going on in pack and how it supports projects and spec files equally.

This is the exact path I followed with the api,

nuget pack my.csproj

This worked great and built me the exact package I expected. I then introduced my first code change that I would deploy through nuget. This started me on working on my environment so that I can build the package on the post build event.

I start working on the post build script and find it fails due to the post build calling a build. At this point I was like well I know I can generate nuget from the nuspec file (as this was the original method) and I have this package already that has a ready to go nuspec file for me. I pull the nuspec file out of the nupkg and set it along side my.csproj.

nuget pack my.nuspec

This packages everything in the folder, entirely not what I want. This extremely confused me that from my original understanding of nuget which is the nuspec file determines everything that goes into the nupkg so when I got entirely different results when I packed against the nuspec that I had surmised the only explanation is that some of the other files in the nupkg were stealing responsibilities of the nuspec file and that this was an unexplained derivation of the nuspec.

Eventually I was able to conclude the real differences were isolation, that the operation wasn't actually directly occurring in the project root but in the bin\[Conf] folder.


Now would any of this had happened if I was able to directly call nuget pack from a post build event, it doesn't seem like it would have.

However with all that has occurred it has definitely given me a much clearer understanding of nuget's workings. What I feel at this point is that the nuspec file itself could be the problem at this point. The nuspec file as of v1.3 is almost an after thought, that the assemblyinfo is really in charge. It seems like you could completely do away with the need for it (other than at package time to be the true manifest of the zip file) if there were a couple of attributes created to lift the last pieces of information that relegated to the nuspec file like the licenseUrls, and the file definitions.

Some thoughts on the file definitions / excludes, perhaps like

[assembly: NugetFileExclude("obj/*")]

[assembly: NugetFile("readme.txt*")]

[assembly: NugetFile("backup.exe*", SourceType.Tool")]

I don't see why these attributes themselves couldn't be released as a nuget package then.

Coordinator
May 11, 2011 at 12:11 AM

Now would any of this had happened if I was able to directly call nuget pack from a post build event, it doesn't seem like it would have.

There’s a bug logged to change this. We will make it so we don’t build by default but instead, you must specify a –build command.

May 22, 2012 at 7:35 PM

Pulling this up from the grave, I can say this experience has been SIGNIFICANTLY IMPROVED.

Combined with Nuget package restore I was able to drop my bat file usage. I was able to setup a nuget package to be built simply as a post build operation using this repeatable post build op:

$(SolutionDir).nuget\Nuget.exe pack $(ProjectPath)  -Verbose  -Properties Configuration=$(ConfigurationName)

Sep 18, 2012 at 9:10 PM

So I've been lurking around here, and on Jabbr.net as well as on Twitter and I keep coming back to this "dead" post. My issue is that I grabbed nugetter from codeplex and used that with the TFS Versioning workflow to attempt to get an automated CI build, with a package creation...all in one step. And it fails. It fails miserably because nugetter actually calls nuget pack <projName>.nuspec and the replacement tokens in the auto-created file just fail to be replaced.

So I'm with you. This work flow is...well, you get the idea..

I'm going to try to get your post build step working again in my CI environment but I don't have much confidence.

I need to basically script the hell out of everything to get build numbers to line up, nuget packages created, and then deployed to the internal repo we have.

I find this all to be Sub. Optimal.

P