How to create an adapter for the TFS Integration Platform - Part IX: IServerPathTranslationService

Note: This post is part of a series and you can find the rest of the parts in the series index.

IServerPathTranslationService takes the path to your source control item and translates it into a platform-neutral path—and vice versa. An example: if you move files between Windows and Linux, the Windows path might be c:\RangersCode\My Production\, while the equivalent on Linux would need to become /src/RangersCode/My Production/ to handle the differences. You need to first change it to a neutral path.

The amount of sleep I lost over path translation is embarrassing because, while the concept is dead simple, applying it correctly is ridiculously hard. The de facto guide on how this should work is Willy-Peter Schaub’s blog post, though there is also an update—based on my many questions—which you may want to read.

This is needed only for VC adapters; if you’re creating a WI adapter, you can skip this section.

Power Tip: The neutral path—or canonical path, as it’s correctly named—is “Unix-like” (i.e., /src/project/). However, these don’t follow all the same rules as true Unix paths. For example, a colon (:) is a valid character in the path.

The two methods you must implement are:


TranslateToCanonicalPathCaseSensitive

This method requires you to provide a neutral path for one of your paths. In my case, it’s simply adding a leading slash to the item’s URL:

public string TranslateToCanonicalPathCaseSensitive(string serverPath)
{
    TraceManager.TraceInformation("WSSVC:TranslationToCanonical - {0}", serverPath);
    string localPath = string.Format(CultureInfo.CurrentCulture, "/{0}", serverPath);

    TraceManager.TraceInformation("WSSVC:New:{0} -> {1}", serverPath, localPath);
    return localPath;
}

TranslateFromCanonicalPath

This method reverses TranslateToCanonicalPathCaseSensitive: it takes a neutral path and provides one that applies to your adapter. In my case, it means dropping the first character and ensuring an absolute URI:

public string TranslateFromCanonicalPath(string canonicalPath, string canonicalFilterPath)
{
    TraceManager.TraceInformation("WSSVC:TranslationFromCanonical - {0} - {1}", canonicalPath, canonicalFilterPath);
    string result = new Uri(canonicalPath.Substring(1)).AbsoluteUri;

    TraceManager.TraceInformation("WSSVC:TranslationFromCanonical:Result {0}", result);
    return result;
}

First in the Platform’s Eyes

Here’s something interesting about server path translation: the platform creates this class first—before anything else, like the configuration service. It must rely on minimal (or ideally none) external information. During creation, it also takes the root path from the filter items in your configuration and passes it to TranslateToCanonicalPathCaseSensitive to get the root neutral path. It needs this because it will strip this information out when passing paths to other adapters and re-add it when they send paths back to you.