TFS Max Path mitigation via check-in policy

This post applies mostly to Team Build 2005 but users of later versions of TFS may find this useful as well.

If you are working with Team Foundation Server 2005 you will eventually hit a build break or have a check in fail because the full path(e.g. c:\foo\bar.txt) exceeds the TFS maximum file path of 260 characters. 

To jog you memory a build error caused by hitting Max Path will look something like this below

Microsoft.TeamFoundation.Build.targets(329,5): error : TF10128: The path [c:\source\(+250 more characters)] contains more than the allowed 260 characters. Type or select a shorter path.

There are many posts on why this is the case and the origin of the issue.  I've included links at the end of this post if you want to spelunk into that. 

This post is about one strategy that you can use to reduce the chance that you will hit this class of build error before the "max path" code is even checked in.

Create a MaxPath check-in policy

Create a MaxPath check-in policy that alerts the user if their check in approaches some predefined threshold that your team has established.   The policy will alert the engineer, at check in time, that the path for their check-in exceeds, say 200 or 220 characters, whatever the number of characters which you have defined as "too close" to the established TFS Max Path of 260 characters.  The check-in is blocked until they reduce the path of what they are checking in or choose to override the policy violation.

 

clip_image001The UI to the left could be used to edit the max path "threshold" to be configurable.  In one deployment of this I created this UI and stored in HKLU\Software\[company]\Custom\TeamFoundation\SourceControl.  If you want to eliminate the UI you can use the defaultMaxPath and remove the form showDialog() in the Edit method in the sample code below

 

 

Sample source code for this, posted below, is mostly from the https://msdn.microsoft.com/en-us/library/bb668980.aspx with changes made to the policy evaluation method.

Source code

 using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.TeamFoundation.VersionControl.Client; 

namespace TfsBuildUtilities
{
    [Serializable]
    public class CheckForMaxPathPolicy : PolicyBase
    {
        //registry location where policy defined max path is stored
        public static string configReg = @"Software\[company]\Custom\TeamFoundation\SourceControl";
        public static int defaultMaxPath = 220; 

        public override string Description
        {
            get { return "Detects if check in will approach TFS version control MAX PATH of 260 characters.  The threshold for this detection is configurable."; } 

        } 

        // This is a string that is stored with the policy definition on the source
        // control server. If a user does not have the policy plug-in installed, this string
        // is displayed.  You can use this to explain to the user how they should 
        // install the policy plug-in.
        public override string InstallationInstructions
        {
            get { return "To install this policy, read \\\\[your server]\\[your share]\\InstallInstructions.txt or contact your local build contact."; }
        } 

        // This string identifies the type of policy. It is displayed in the 
        // policy list when you add a new policy to a Team Project.
        public override string Type
        {
            get { return "MAX PATH detection"; }
        } 

        // This string is a description of the type of policy. It is displayed 
        // when you select the policy in the Add Check-in Policy dialog box.
        public override string TypeDescription
        {
            get { return "This policy will detect if a check in will approach TFS version control MAX PATH of 260 characters."; }
        } 

        // This method is called by the policy framework when you create 
        // a new check-in policy or edit an existing check-in policy.
        // You can use this to display a UI specific to this policy type 
        // allowing the user to change the parameters of the policy.
        public override bool Edit(IPolicyEditArgs args)
        {
            // Do not need any custom configuration
            TfsBuildUtilities.frmCheckForMaxPathPolicy frmSettings = new TfsBuildUtilities.frmCheckForMaxPathPolicy();
            frmSettings.ShowDialog();
            return true;
        } 

        // This method performs the actual policy evaluation. 
        // It is called by the policy framework at various points in time
        // when policy should be evaluated. In this example, the method 
        // is invoked when various asyc events occur that may have 
        // invalidated the current list of failures.
        public override PolicyFailure[] Evaluate()
        {
            int userMaxPath;
            try
            {
                //try to read user config max path setting from registry
                Microsoft.Win32.RegistryKey key;
                key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(TfsBuildUtilities.CheckForMaxPathPolicy.configReg);
                userMaxPath = Int32.Parse(key.GetValue("userMaxPath").ToString());
            }
            catch
            {
                userMaxPath = defaultMaxPath;
            } 

            List failures = new List(); 

            foreach (PendingChange change in PendingCheckin.PendingChanges.AllPendingChanges)
            {
                if (change.ServerItem.ToString().Length >= userMaxPath)
                {
                    failures.Add(new PolicyFailure(
                        change.FileName.ToString() + " path length of " + change.ServerItem.ToString().Length.ToString() + " exceeds MAX PATH threshold of " + userMaxPath + ".  Full server path is " + change.ServerItem.ToString(), this));
                }
            }
            return failures.ToArray();
        } 

        // This method is called if the user double-clicks on 
        // a policy failure in the UI. In this case a message telling the user 
        // to supply some comments is displayed.
        public override void Activate(PolicyFailure failure)
        {
            MessageBox.Show("Please reduce the file or directory name length to less than 260 characters", "How to fix your policy failure");
        } 

        // This method is called if the user presses F1 when a policy failure 
        // is active in the UI. In this example, a message box is displayed.
        public override void DisplayHelp(PolicyFailure failure)
        {
            MessageBox.Show("This policy detects if your check in is approaching the TFS Version control MAX PATH of 260 characters and and reminds you to reduce the file and directory length.", "Policy Help");
        }
    }
}

Conclusion

Users working with TFS may check in code that approaches the TFS Max Path of 260 characters.  This will cause build errors when synchronized on a build machine where the local work space makes the path to the file more than 260 characters.  A mitigation for this can be to put in a check-in policy that blocks check-ins that exceed your defined max path threshold.

Feedback and your own experience on this subject is always welcome.

Reference

More description on Max Path limitation in TFS - https://blogs.msdn.com/aaronhallberg/archive/2007/06/20/team-build-and-260-character-paths.aspx

Origin of long file limitations in the .Net Base Class Libraries - https://blogs.msdn.com/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx

Deploying a custom check in policy assembly - https://msdn.microsoft.com/en-us/library/ms181281(VS.80).aspx

Custom policy sample code - https://msdn.microsoft.com/en-us/library/bb668980.aspx