Category Archives: development

TypeScript build system for Sublime Text 2

Recently I decided to create a small Node.JS project. And I like strongly typed languages. I know I can’t get the full strong typing in JavaScript and having the power of it. So I decided to use TypeScript for the project. I chose Sublime Text 2 as an editor, I am used to use Visual Studio but in I wanted to take a grip of an editor that as I read “everyone loves”.

After downloading all the required bits I got to build (Ctrl+B) the project and ran into this error:

error TS5037: Cannot compile external modules unless the '--module' flag is provided.

This is easy to fix when you are building TypeScript project from command line:

tsc --module commonjs app.ts

This is the original typescript.sublime-build file I downloaded from the Internet:

{
  "cmd": ["c:\\Users\\user\\AppData\\Roaming\\npm\\tsc.cmd", "$file"],
  "file_regex": "(.*\\.ts?)\\s\\(([0-9]+)\\,([0-9]+)\\)\\:\\s(...*?)$",
  "selector": "app.ts"
}

and the fix is very simple (but it took me quite a while to figure it out) – just add new items ("--module" and "commonjs") to cmd array:

{
  "cmd": ["c:\\Users\\user\\AppData\\Roaming\\npm\\tsc.cmd", "--module", "commonjs", "$file"],
  "file_regex": "(.*\\.ts?)\\s*\\(([0-9]+)\\,([0-9]+)\\)",
  "selector": "app.ts"
}

I had to modify the file_regex too, because it was not working.

Building solution with multiple NuGet package projects on TeamCity

Let’s say you have a solution with projects in it and some projects represents NuGet packages. I know it is not ideal, but the NuGet package project are really small and I didn’t want to create solution for each individual project. And also they are share some code. And I didn’t want to publish all the packages when I made changes to one project only not affecting the others

A good example is a solution with UI controls – each project representing a group of UI elements or a single element. Like set controls from a big controls vendor – I imagine the solution is quite big with projects like grid control, map control, charting, etc. By adding a NuGet package projects you can keep these distributed separately – one package for grid (ComponentVendor.UI.Grid), one package for maps (ComponentVendor.UI.Maps), etc. End-users do not have to download one big massive package (ComponentVendor.UI) which will make them to delete the unused references later.

The solution structure

UI
  SharedCode
  Maps
  Maps.NuGet (references Maps)
  Grid
  Grid.Nuget (references Grid)
  ...

The first step was to create a TeamCity project for the solution and build configurations for:

  • root – build the entire solution (that’s why you set up the CI build) with VCS root pointing to source control root of the solution and with UI.sln as build file
  • all packages – manually triggered distribution all the packages at once
  • each NuGet package project

Setting up the build configuration for NuGet package project:

build steps

  • create new VCS root that points to the project source control directory to “isolate” this project from changes made in other projects
  • add VCS root checkout rule: +:.=>ProjectDirectory, this will checkout the sources into this directory NuGet build step
  • set MSBuild build file to .csproj file
  • add build step to create NuGet package with .csproj file as specification file and ProjectDirectory as base directory NuGet build step

The build and publication of the package is triggered by changes made to package project, for example by changing the package version.

Sharing NuGet repository across multiple solutions II

Second step: Fixing the HintPath of referenced assemblies

All distributed assemblies from the NuGet package are added as references to the project. NuGet sets the HintPath of the reference with relative path (relative to the packages directory). When using a shared repository as described in previous post this brings some problems.

Problem with CI builds

The shared repository is stored somewhere on your machine and all project references added by NuGet should point there. You usually don’t clone your development machine directory structure on your CI server. The CI build will fail because the assemblies were not found (but they are there in the directory).

Problem with package restore

Even NuGet package restore feature won’t help because it only downloads the missing packages and places them by default under packages directory in solution directory. But it does not change the HintPaths of referenced assemblies. You can’t event set the MSBuild project property AdditionalLibPath because you don’t know all the directories where the package DLLs are placed beforehand (of course I can create a build task).

The solution to this is very easy, I found this discussion where a build property is used in HintPath. I had to extend it a little to support both local and CI builds and turn the package restore on.

<PropertyGroup>
 <PackagesDirectory>path to shared packages directory</PackagesDirectory>
</PropertyGroup>
<PropertyGroup Condition="Exists('$(PackagesDirectory)')">
  <NuGetPackagesDirectory>$(PackagesDirectory)</NuGetPackagesDirectory>
</PropertyGroup>
<PropertyGroup Condition="!Exists('$(PackagesDirectory)')">
  <NuGetPackagesDirectory>$(SolutionDir)\packages</NuGetPackagesDirectory>
</PropertyGroup>

This setting covers both features – local development and CI build. Value of NuGetPackagesDirectory property will be set to the path to the shared directory (verified by Condition="Exists('$(PackagesDirectory)')") on local machine. On CI server this directory might or might not exist. If it does not exist it will be set to a packages directory under solution folder (used by package restore).

And the reference to NuGet package DLL

<Reference Include="NLog">
  <HintPath>$(NuGetPackagesDirectory)\NLog.2.0.1.2\lib\net40\NLog.dll</HintPath>
</Reference>

The branch and changset details are available here.

Sharing NuGet repository across multiple solutions

I’ll start with be summary BenPhegan posted to a thread I started on NuGet CodePlex site.

  1. Developers are historically used to having a local common library location for all their binary dependencies (ie all hintpaths reference “d:\common” or something similar).
  2. Often this library is controlled centrally and xcopy/robocopied to all developers machines to provide commonality of build capability, generally the central copy come from a CI build system.
  3. There are a lot of different projects that a developer works on with a lot of dependencies, and it is seen as efficient to have a single copy of these dependencies on disk.
  4. Project files are included from multiple solutions at arbitrary locations on disk, resulting in mismatched relative hintpaths when using NuGet.

The problem (not the only one) with shared packages directory is that every project that ever loaded a NuGet package creates a record in repositories.config file. You end up with this file containing lots of these. Also some packages directories might get deleted when a package is removed.

First step: Solution-level repositories.config file

My first approach to an “enterprise” NuGet was to get rid of the repositories.config file that is located under packages directory. All the packages.config files can be discovered by iterating through all projects in the solution:

const string fileName = "packages.config";
foreach (var project in solutionManager.GetProjects())
{
  var projectItem = project.FindProjectItem(fileName);
  if(projectItem == null)
  { 
    continue;
  }

  // we have the packages.config file here
}

But then I thought about it and got the idea that I can make repositories.config file local to a solution, i.e. put it in solution scope. And the best place to put NuGet specific file is the .nuget directory. The entries in config file are added with path relative to solution folder.

Solution
  .nuget
     nuget.config
     nuget.exe
     nuget.targets
     repositories.config
  ProjectA
  ProjectB
  packages.config

Now there’s one repositories.config file for every solution containing the records for every available packages.config. Package files in shared directory can be still deleted when the package in repository is no longer needed (this feature can be turned off and shared repository must be cleared manually).

Vote for it on NuGet!

I tried to avoid big changes in NuGet codebase and I was slowly getting to understand how NuGet internals works. Next step was to force NuGet to use the shared packages repository. I changed some classes (get the settings from registry) to find out the only thing I have to do was to add a node to C:\Users\(your name)\AppData\Roaming\NuGet\NuGet.config configuration file. Don’t forget to remove any repositoryPath from a Nuget.config file under your solution directory if you have one.

<config>
  <add key="repositoryPath" value="path to your repository"/>
</config>

The branch and changset details can be viewed on CodePlex here.

The description of how to build (locally and CI) a solution with project(s) referencing assemblies in a shared local directory will follow.

Data-driven Knockout views II

Last time I posted a code snippet with description of data driven Knockout views. I have modified and simplified it and

  • added support for forEach binding and
  • the type member of ViewModel class can return a function that is evaluated for every item in collection

This brings even more flexibility, the view model itself can decide which view to use based on a value returned from type function.

contentBindingHandler.jsview rawview file on Bitbucket

The example will follow soon.

Data-driven Knockout views

I’m using Caliburn.Micro in my Silverlight and WPF projects. I fell in love with Caliburn automagic – view locator, auto binding, etc. For my NodeJS project I was looking for JavaScript library supporting MVVM pattern and I found KnockoutJS.

Knockout has very nice feature called binding with a simple way of implementing your custom binding.

What I was missing was Caliburn’s binding/convention for ContentControl – data driven view rendering:

<!-- DataContext is RootViewModel -->
<ContentControl Name="ChildViewModel" />

with the view located for value of ParentViewModel.ViewModel property and then rendered.

The solution I come with uses

  • Infuser as a templating engine, more on using Infuser as templating engine for Knockout here
  • TrafficCop used by Infuser and prevents duplicate AJAX requests

Infuser is configured to load the view templates from views directory (I will implement some view locator later):

infuser.defaults.templateSuffix = ".tmpl.html";
infuser.defaults.templateUrl = "/js/app/views/"; 

and every view model object must have a property returning its type name (if someone knows about better way how to do it, please let me know).

var SampleViewModel = kb.ViewModel.extend({
  constructor: function(model) {
    ...
    this.type = 'SampleViewModel';
  }, 
  ...
}

Code of the binding handler:

ko.bindingHandlers.content = {
  'init': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    var options = ko.utils.unwrapObservable(valueAccessor())
    var templateName = options.data.type.replace(/viewmodel/ig, 'View'),
      dataValue = ko.utils.unwrapObservable(options['data']);
    var innerBindingContext = bindingContext['createChildContext'](dataValue, options['as']);
    ko.renderTemplate(templateName || element, innerBindingContext, options, element);
  }
};

and the HTML

<div data-bind="content: { data: childViewModel }"></div>
<script>
  var rootViewModel = kb.ViewModel.extend({
    constructor: function(model, options) {
      this.childViewModel = new SampleViewModel();
    }
  });
  ko.applyBindings(rootViewModel);
</script>

NuGet pack error “Assembly outside lib folder”

When I was working on a NuGet package I noticed that some DLLs (that were not supposed to be placed there) were copied into the content subdirectory of the package.

Added file 'content\lib\Microsoft.Practices.EnterpriseLibrary.Common.dll'.

And that also caused an issue:

Issue: Assembly outside lib folder.
Description: The assembly 'content\lib\Microsoft.Practices.EnterpriseLibrary.Common.dll' is not inside the 'lib' folder and hence it won't be added as reference when the package is installed into a project.
Solution: Move it into the 'lib' folder if it should be referenced.

It took me some time to figure out that NuGet copies all project items with BuildType set to Content to content directory in package. Problem was solved by changing BuildType to None.

How I failed using MSTest on TeamCity without Visual Studio

I was setting up a continuous integration for one project. I have configured a build step in TeamCity to build the solution and another to execute unit tests using MSTest. And that failed – the reason was Visual Studio was not installed on that machine. I googled around and found some useful posts:

The key components for running tests are MSTest.exe and QTAgent.exe. So I copied all the files to desired locations, I didn’t added the DLLs to GAC, opened command line and executed MSTest.exe and …

… an exception! Could not load file or assembly xxx.dll

So I found that DLL on my computer and copied it to directory with MSTest.exe, then fired MSTest.exe and another assembly load exception and again and again.

Because I could I installed VS.NET 2012 on that machine just to avoid this eternal cycle.

For those who can’t I used Fusion Log Viewer (fuslogvw) to log all assembly bindings to disk and then analyzed the files in LinqPad to get the list of loaded DLLs and their locations. See the attached file (some of the binded DLLs might be required by the tested project).

Hope this will help someone.