Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attempting to retrieve files from TFS workspace stalls application

Tags:

c#

tfs

tfs-sdk

So I am attempting to retrieve the files from a workspace in TFS. Unfortunately, every attempt that I have made to do this results in a stalled application. As of right now, this is the code:

    public void GetWorkspaceFiles(string workspaceName)
    {
        VersionControlServer sourceControl = (VersionControlServer)TfsServer.GetService(typeof(VersionControlServer));

        var items = sourceControl.GetItems(workspaceName, VersionSpec.Latest, RecursionType.Full)
                                 .Items
                                 .Where(x => x.ItemType == ItemType.File)
                                 .ToList();

        for (int x = 0; x < items.Count; x++)
            items[x].DownloadFile();

What happens is that every time I run this application (on multiple machines) it stalls on items[x].DownloadFile(). All the files in TFS are not locked, everything is fine. Attempting to use the Workspace.Get() method results in the same thing.

If I hit pause, x will be a specific value, but I can't access the items collection, as when I do I get "Cannot evaluate expression because the current thread is in a sleep, wait, or join". When I evaluation the call stack I get:

[In a sleep, wait, or join]
[External Code]
GetWorkspaceFiles(string workspaceName) Line 55

I am at a loss at what to do further. Whenever I pause the application, x is always at the same value (the value that it stalls on is different for every application run though).

Anyone have any ideas?


Edit: After adding diagnostic logic (based on the link in Grant's answer) I am even more confused than ever.

The workspace I am passing into this method is $/QA/Automated Test Scripts/Regression or System Test Scripts/RDE or Condo (verified through the debugger).

However, when I look at the tfs logs, it looks to be downloading the code file that I am running, as it says:

02/10/2011 12:26:58 (pid 5808, tid 5968, 42180 ms) Recording OperationStatus.Getting for $/QA/Automated Test Scripts/QA Tools/Test Manager/Test Polling Server/fmMain.cs

Right after that entry is:

02/10/2011 12:26:58 (pid 5808, tid 5968, 42180 ms) DownloadFiles: 18 ms
02/10/2011 12:26:58 (pid 5808, tid 5968, 42181 ms) Acknowledgements: 0 ms

After that there are no further updates to the log file, and my application is stalled. What I am confused about is

1) Why is this trying to pull the application code from TFS when I am specifying a completely different TFS workspace

2) Why is this stalling after attempting to retrieve the file? It's possible that it's because fmMain.cs is open in Visual Studio, but it should still exception out and not get hung up. I'm able to get latest while the file is open via visual studio normally.



Edit2:

Ok so I was reading through MSDN and I noticed that the workspace name can be the local path to the files. So I modified what I passed in as the workspaceName parameter to the local directory of the files. I still get stalls, but the log file is a lot less clear on why. I have uploaded the tf.log file here (I have obviously changed proprietary information, such as server and project names, but everything else is untouched). After that last log entry, no further data is written to the log.

like image 303
KallDrexx Avatar asked Feb 10 '11 14:02

KallDrexx


2 Answers

GetItems doesn't take a workspace name, it takes a server path to get a list of files. if you're trying to get a copy of files from a specific area, what you want to do is:

  var items = sourceControl.GetItems("$/Project/Path/subpath"/et cetera", VersionSpec.Latest, RecursionType.Full)
                                 .Items
                                 .Where(x => x.ItemType == ItemType.File)
                                 .ToList();

When you call

items[x].DownloadFile();

it is returning you a stream, not actually downloading the file to disk. If you want to write the file to disk at that point, you'll need to do normal stream handling stuff to write it out.

If you are actually trying to get files from TFS into a workspace, it's a little different.

        VersionControlServer sourceControl = coll.GetService<VersionControlServer>();

        var ws = sourceControl.QueryWorkspaces(workspaceName, null, null);

        var status = ws[0].Get();

(Error handling needs added to this)

This will refresh your workspace with files from the server. It will work just like the Visual Studio UI, in that it will compare what's currently on disk with what is in the repository, and will update the local version if a newer version exists.

There are a number of overloads to the Get() method that you can use to specify the exact behavior you are looking for.

--Edit--

When you call Workspace.Get(), the first thing it does is go out to TFS (using a web service call) and gets a list of files. Then, it iterates through those files, comparing what you have already "gotten" in that workspace, to what is at the revision you requested (or VersionSpec.Latest if you didn't specify any other revision).

This process can take a while. It's just like right-clicking and getting latest on every mapped directory in your workspace.

If your workspace is mapped to $/, it's going to iterate through all files in TFS. If you have multiple mappings of paths to local paths, it will go through each one, and it will retrieve and save locally any files that you haven't already gotten.

Refreshing an entire workspace can take a very long time unless you are careful on what you have mapped.

-- EDIT 2 --

If you're looking to limit what you're getting, you have a couple options. The first option is to limit the mapping within the workspace that you are accessing. For example, if your workspace has only one mapping to $/Project/Branch/Source/Utilities/MyUtility, only the files in that mapping will be gotten.

In a couple of our in-house utilities, we even go so far as to:

  • Dynamically create a workspace
  • Map paths to directories for only those paths that we need to get
  • Do a get
  • Edit certain files (using the PendEdit() method)
  • Check in the changed files
  • And, finally, remove the workspace

This is a lot of work if you're just trying to automate refreshing a set of files, so what you can do is pass in a path to the Get() method:

var status = ws[0].Get(new GetRequest("$/path/to/subfolder", RecursionType.Full, VersionSpec.Latest),
                   GetOptions.Overwrite);
like image 131
Robaticus Avatar answered Sep 27 '22 21:09

Robaticus


Does the same command/parameters work when using the TFS command-line tools? e.g. TF.exe get ?

Do you have any anti-virus software installed? Is it possible that it's getting in the way? Try temporarily disabling it.

You can also enable TFS Client-Side tracing in your app.config to see what's going over the wire: http://blogs.msdn.com/b/edhintz/archive/2007/03/30/tfs-client-tracing.aspx

like image 37
Grant Holliday Avatar answered Sep 27 '22 22:09

Grant Holliday