How do I resolve the root and relative paths of TFS folders on the server?

Prisoner ZERO picture Prisoner ZERO · Jan 26, 2015 · Viewed 7.4k times · Source

I have created a CodeActivity for use in (custom) build definitions. This activity needs to copy files located on the server to/from places like the 'source directory', 'custom folders' to the 'drop directory' (etc.) before executing its primary purpose.

Some of the variables I have are valid paths, but others are obviously placeholders for 'relative paths'. However, I need the physical server path so I can copy useful items to-and-fro.

I NEED THINGS LIKE:

  • The physical path for the projects root (see image below)
  • To be able to resolve the physical path to custom folders (see image below)
  • It would be nice to be able to resolve physical paths from 'relative paths'

Of course, I could pass the project-name into the activity (for parsing purposes)...because that would just be 'cheesy'.

MY QUESTION(S) ARE:

  • How do I resolve the physical path to the TFS project root?
  • Once I resolve the root, can I rely on it to 'build' paths to custom folders?
  • How do I get the server paths from relative paths like '$/Test/Drops'?

SOME EXAMPLES OF THINGS I KNOW HOW TO GET:
These items are somewhat useful, while others...not so much. Unless, I can use them to get the physical server paths.

BuildDirectory:
'F:\bld\Builds\41\Test\Test_CustomActivity_CreateNuGetPackages'

BuildDetail.DropLocationRoot:
'$/Test/Drops'
...wish I had the physical path

BuildDetail.BuildController.CustomAssemblyPath:
'$/Test/BuildProcessTemplates'
...wish I had the physical path

SourcesDirectory:
'F:\bld\Builds\41\Test\Test_CustomActivity_CreateNuGetPackages\src'

Workspace.Folders:
'F:\bld\Builds\41\Test\Test_CustomActivity_CreateNuGetPackages\src\Test\NuGet.Research\net35'

SOME EXAMPLES OF THINGS I WANT:
enter image description here

UPDATE: 2/2/2015
@Edward - per your request. Below is a more detailed explanation of what I am trying to accomplish.

enter image description here enter image description here

Answer

Edward Thomson picture Edward Thomson · Jan 26, 2015

Let me preface this answer by saying that there's a lot of terminology overload going on, so I want to define a few things:

  • Server path: the path to the file or folder in the version control system. For example, $/Test/BuildResources is a server path. This is an absolute server path, it is not relative.
  • Local path: the path that you have mapped the server path to on your machine. For example, D:\Test\BuildResources or /home/me/test/buildresources is a local path.
  • Mapping: the correspondence between the server paths and local paths - so that TFVC knows where to put files on your local machine when you do a "get".

I define this not to be pedantic, but because having the terminology correct will be helpful when using the TFS SDK, which will let you query the local path for a given server path (and vice versa) easily. (You should not simply concatenate path components together, since TFVC allows for very complex workspace mappings.)

To get started with the TFS SDK, you first need to find the server connection information. If you have a given local path (in this case, your SourcesDirectory) you can use that to read the workspace cache and get the information you need for the server connection that the build server has created:

// Get the workspace information for the build server's workspace
var workspaceInfo = Workstation.Current.GetLocalWorkspaceInfo(sourcesDirectory);

// Get the TFS Team Project Collection information from the workspace cache
// information then load the TFS workspace itself.
var server = new TfsTeamProjectCollection(workspaceInfo.serverUri);
var workspace = workspaceInfo.GetWorkspace(server);

Once you have a workspace, you can query it for the path mappings. It will do the necessary translation from server to local path based on your workspace mappings. For example:

workspace.GetServerItemForLocalItem("D:\My\Local\Path");

and

workspace.GetLocalItemForServerItem("$/My/Server/Path");

This mechanism will only work, however, if your build definition actually sets up the workspace to include these files. If you need some directory $/Foo/Bar, you will need to make sure that it is included in the Source Settings details tab of the Build Definition.