Monday, January 30, 2012

Did you know? – Editing nodes with JsTree

For one of the Confluence plugins that I developed (Tags Plugin), I needed a client side tree. After a little research I decided to use jsTree. This is a jQuery plugin that is feature reach and so far I have been able to customize for my needs.

One of the features that I wanted was to allow users to edit a node on the tree when they double click it. It turn out to be super simple, first here the tree declaration (simplified from tag-macro.view.js):

treeContainer.jstree({
"json_data": {
"data": [ that.getTreeNodes() ]
},
"crrm":{
"input_width_limit":2000
},
"plugins": ["json_data", "ui", "crrm" ]
})

The important bit is to include the “crrm” plugin, I customized it to increase the size of the input field when the node is in edit mode. Once this is setup, putting a node into edit mode is as simple as:

$('.jstree-leaf').live('dblclick', function(){
treeContainer.jstree("rename");
});

Yeah, yeah, “live” is deprecated, but as far as I know the jQuery version provided by Confluence is not the lastest. This will auto-magically set the node to edit mode and listen for the ENTER key to trigger the “rename.jstree” event. So, how do you handle this event? You bind to the event when you declare the tree:

treeContainer.jstree({
//...
})
.bind("rename.jstree", function(e, data){
var oldText = data.rslt.old_name;
var newText = data.rslt.new_name;
//do your thing
});

If you need a client side tree, you may want to give jsTree a shot.
tags-test

Did you know? – NuGetGallery Build (part 7)

Now I feel like we took a big step forward, at the end of the previous post we kicked off the build process after all the packages where restored using Nuget.exe. Now, the regular “Build” target will compile the website project. What’s next? Well, let’s go back to NuGetGallery.msbuild (simplified):

<Project DefaultTargets="Build">
<UsingTask AssemblyFile="../3rdParty\xunit\xunit.runner.msbuild.dll" TaskName="Xunit.Runner.MSBuild.xunit" />

<Target Name="Build" DependsOnTargets="Clean">
<MSBuild Projects="..\NuGetGallery.sln" Targets="Build" Properties="Configuration=$(Configuration);CodeAnalysis=true;" />
</Target>

<Target Name="RunFacts" DependsOnTargets="Build">
<xunit Assembly="..\Facts\bin\$(Configuration)\NuGetGallery.Facts.dll" Xml="NuGetGallery.Facts.results.xml" />
</Target>

<Target Name="FullBuild" DependsOnTargets="RunFacts;UpdateDatabase" />
</Project>

Let’s assume that the “Build” target just finished. I am going to skip the “CodeAnalysis=true” that you see as part of the properties for the build and move to the next target in the sequence: “RunFacts”. This is where the unit tests are run and its pretty simple.

Since the solution also contains a NuGetGallery.Facts project this is included in the output of the build. All that happens in the “RunFacts” target is a call to the XUnit task passing the location of the assembly that contains the unit tests (NuGetGallery.Facts.dll). Where does this task come from? You can see the “UsingTask” directive at the top of the file that points to the assembly in the “3rdParty” directory that contains the task.

Could this be the reason why XUnit itself was not included to be downloaded using nuget.exe like the other packages? Perhaps MSBuild needs to load the task at the moment when is parsing the project file so it already needs to be there? Mmh…

Thursday, January 19, 2012

Did you know? – NuGetGallery Build (part 6)

Last post left off where NuGet.exe was used to download all packages before compiling the project. Let’s talk a little bit about conditions. If you remember from NuGet.targets, here is the target that restores the packages:

<Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
<Exec Command="$(RestoreCommand)"
LogStandardErrorAsError="true"
Condition="Exists('$(PackagesConfig)')" />
</Target>

I skipped over its DependsOnTargets=”CheckPrerequisites” attribute, this target is defined on the companion NuGet.settings.targets (in retrospect, I don’t know why there are two .target files where it seems that one would have sufficed):

<Target Name="CheckPrerequisites">
<!-- Raise an error if we're unable to locate nuget.exe -->
<Error Condition="!Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
</Target>

This is self explanatory, it will error if Nuget.exe was not found. Furthermore, the “RestorePackages” target will error if the packages.config file is not found.

PS: I did left off one piece of the puzzle: precompiling the razor files before building. This is defined in the RazorGenerator.targets which is also imported by Website.csproj.

Wednesday, January 18, 2012

Did you know? – NuGetGallery Build (part 5)

In the previous post we left off trying to figure out how NuGetGallery downloads its required packages during the build process. We arrived at the file that contains the targets to do this NuGet.targets (simplified):

<Project ToolsVersion="4.0">
<Import Project="NuGet.settings.targets"/>
<Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
<Exec Command="$(RestoreCommand)"
LogStandardErrorAsError="true"
Condition="Exists('$(PackagesConfig)')" />
</Target>
</Project>

Excellent, there’s the definition of a “RestorePackages” target that runs an Exec task which presumably will take care of downloading the packages. The “RestoreCommand” is defined in yet another targets file which is imported at the beginning, NuGet.settings.targets (simplified):

<Project ToolsVersion="4.0">
<PropertyGroup>
<NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath>
<NuGetExePath>$(NuGetToolsPath)\nuget.exe</NuGetExePath>
<PackagesConfig>$(ProjectDir)packages.config</PackagesConfig>
<PackagesDir>$(SolutionDir)packages</PackagesDir>

<!-- Commands -->
<RestoreCommand>"$(NuGetExePath)" install "$(PackagesConfig)" -o "$(PackagesDir)"</RestoreCommand>

<!-- Make the build depend on restore packages -->
<BuildDependsOn Condition="$(RestorePackages) == 'true'">
RestorePackages;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
</Project>

A lot of things happening here:
- There is a property definition to the location of NuGet.exe (which is included in the source)
- There is a property definition to a packages.config, which contains the list of packages that it needs to download.
- There is a property definition to a directory where the packages will be downloaded into.
- Then there is a property definition for the actual restore command, which is a call to Nuget.exe with the “install” parameter.

The next line is probably the most important one, it’s where the target defined previously is glued into the build process. “BuildDependsOn” is a special MSBuild property used to override the sequence of steps during build. In this case it adds the “RestorePackages” target at the beginning.

Don’t get tripped up by the condition included in the “BuildDependsOn” which uses a property with the same name as the target “RestorePackages” (this confused me for a while). Basically we are only going to download the references if the “RestorePackages” property is set to true, which if you remember it was set at the beginning of Website.csproj.

Monday, January 16, 2012

Did you know? – NuGetGallery Build (part 4)

In the last post we left at the point where all previous build output from all projects was deleted. Let’s continue with the build from NuGetGallery.msbuild:

<Target Name="Build" DependsOnTargets="Clean">
<MSBuild Projects="..\NuGetGallery.sln" Targets="Build" Properties="Configuration=$(Configuration);CodeAnalysis=true;" />
</Target>

The msbuild task is invoked again, to run the Build target on the NuGetGallery.sln. This file references the “Website\Website.csproj”, MSBuild runs the Build target on this project.

Now, before it can compile anything it needs to download all the dependencies. Notice that NuGetGallery includes very few assemblies as part of the source, take a look at the “3rd Party” folder to see an unimpressive list of references. The trick is that it uses NuGet.exe to download all the extra references before the build. So how does it accomplish this magic? Let’s take a look at WebSite.csproj (simplified):

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build">
<PropertyGroup>
<RestorePackages>true</RestorePackages>
</PropertyGroup>

<Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
</Project>

Mh, there’s a property called “RestorePackages” that sounds like it’s used to, I don’t know, restoring nuget packages? Remember this one. And at the bottom there is an import of NuGet.targets. That’s where the answers must be!

Saturday, January 14, 2012

Did you know? – NuGetGallery Build (part 3)

In the previous posts we saw how the NuGetGallery build got kicked off by Build-Solution.ps1, which internally went and grabbed the connection string from the website’s web.config using Get-ConnectionString.ps1. At the end of the file it finally calls msbuild.exe passing the NuGetGallery.msbuild file and the connection string (pay special attention to the /t:FullBuild at the end which defines which target to run):

$projFile = join-path $scriptPath Scripts\NuGetGallery.msbuild
& "$(get-content env:windir)\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" $projFile /p:DbConnection=$connectionString /t:FullBuild

Let’s peel another piece of the onion and look at this msbuild file (simplified):

<Project DefaultTargets="Build">
<Target Name="Clean">
<MSBuild Projects="..\NuGetGallery.sln" Targets="Clean" Properties="Configuration=$(Configuration)"/>
</Target>

<Target Name="Build" DependsOnTargets="Clean">
<MSBuild Projects="..\NuGetGallery.sln" Targets="Build" Properties="Configuration=$(Configuration);CodeAnalysis=true;" />
</Target>

<Target Name="RunFacts" DependsOnTargets="Build"> ... </Target>
<Target Name="FullBuild" DependsOnTargets="RunFacts;UpdateDatabase" />
</Project>


This is where it starts to wire up a list of targets to run during the build. As you can see, the “FullBuild” target is empty, but depends on the “RunFacts” and “UpdateDatabase” targets. Working our way back, the “RunFacts” depends on “Build”, which in turn depends on “Clean”.

Phew, maybe we can now do some work? All right, at this point it calls msbuild to run the “Clean” target on the NuGetGallery.sln file. I am going to skip how this part works, the important thing is that all the projects included in the solution will delete all their intermediate and final build outputs. Note: the “Clean” target is defined in “Microsoft.Common.targets” file which lives in your framework directory.

Friday, January 13, 2012

Did you know? – NuGetGallery RequestModels

A while back, while working on ASP.NET MVC, I learned to not pass the business models directly into my Views. Especially if they were Entity Framework entities. So I got in the habit of creating specialized ViewModels for this purpose.

But last week, while reading NuGetGallery’s source, I saw how they took this concept to the next step: RequestModels. You see, for the MVC applications that I wrote I was accustomed to re-using the ViewModel to capture data from the requests, my thinking was “well, I used the ViewModel to generate the response, it’s fitting that it should also be used to receive requests from the page that it created”.

RequestModels
I like the idea of further separating the concerns between the object that is used to create response and the one used to bind to the request. You’ll notice how the RequestModels have the validations from DataAnnotations that are to be used when binding to the request and only have the fields necessary to process each request.

For some reason, the application doesn’t use this extra separation all the time and some times receives the ViewModel (for example in the PackagesController.cs). An oversight?

I am going to play around with this way of organization in my own projects and see how it feels.