Welcome to MSDN Blogs Sign in | Join | Help

Robert Horvick's Weblog

Team Foundation Server administration and setup
MSBuild Task ... validating a source file link exists

Ok, I’m back.  No defects this week though.  I’ve been distracted by MSbuild.

 

If you are not aware MSBuild is the new build platform for Whidbey.  There is some great information about MSBuild here:

 

http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20040122VSNETAK/manifest.xml

 

http://mymsevents.com/MyMSEvents/search.aspx?s=1&keywords=msbuild&keywordtype=1&track=0&speaker=0&timeslot=0&future=0

 

And whatever your opinions this link has links to some great critical thoughts from the Ant community

 

http://www.iunknown.com/000371.html

 

So why do I care about MSBuild?  How can I not care?  If you intend to use Whidbey or develop on Microsoft platforms in the future then you have to care about the build platform you may be working on.  May?  You could still write makefiles.

 

But this blog is not about marketing fluff or towing the line and pimping our products as the greatest thing since sliced bread – it’s about code and code quality.

 

So I started working on a simple task.  This task has the simple goal of enforcing a project standard we have on our team.  Every project must have a link to a file named BldVer.cs.  The file must be a link, not a copy of the file, and the file must be compiled, not just linked content.  Lastly the file must be a link to the right file.

 

Simple?  Yeah, surprisingly so.

 

Here’s an example of one way we could do this … note that a lot of work is done by the base class which I excluded since it’s mostly handling error handling and reporting, data validation and the like.  This is not a complete method (there are other edge conditions I care about and I moved some hardcoded strings and logic into the sample class to make it easier to read) but is a straight forward example that hopefully shows that tasks are useful for more then simply copying files.

 

using System;

using System.IO;

using System.Collections.Generic;

using System.Resources;

using Microsoft.Build.Framework;

 

namespace MBFProjectLint

{

      public class BldVerIsLink : MBFLintTask

      {

            List<ITaskItem> m_sources = new List<ITaskItem>();

 

            const string BldVer_File = "bldver.cs";

            const string BldVer_Path = @"build\bldver";

 

            public override bool Execute()

            {

                  bool foundBldVerLink = false;

                  bool foundBldVerNotLink = false;

                  bool foundBldVerLinkSubtypeCode = false;

                  bool BldVerLinkIsToWrongFile = false;

 

                  foreach(ITaskItem ti in m_sources)

                  {

                        string link = ti.GetAttribute("Link");

                        if (link != null)

                        {

                              // we have a linked file, this is possibly a match.

 

                              if (link.ToLower() == BldVer_File)

                              {

                                    // the linked file is BldVer.cs

 

 

                                    string subtype = ti.GetAttribute("SubType");

                                    if (subtype != null)

                                    {

                                          /* Validate SubType.  This could be empty but we should always

                                           * specify Code to ensure that future compiler or project

                                           * defaults don't break us

                                           */

                                          foundBldVerLinkSubtypeCode = subtype.ToLower() == "code";

                                    }

 

                                    /* This will return false if InetRoot is null, or if the

                                     * path does not exist.  This will also take care of

                                     * producing an error message to the build engine

                                     */

                                    if (DemandInetRoot())

                                    {

                                          // In this context Identity is the path to the file.

                                          string bldVerRelativePath = ti.GetAttribute("Identity");

 

                                          if (bldVerRelativePath != null)

                                          {

                                                // rooted path to the file we should link to

                                                string realBldVerPath = Path.Combine(InetRoot,

                                                                                          Path.Combine(BldVer_Path, BldVer_File));

 

                                                // rooted path to what we are linking too

                                                string rootedBldVerLink = Path.GetFullPath(bldVerRelativePath);

 

                                                // they had better match

                                                if (realBldVerPath.ToLower() != rootedBldVerLink.ToLower())

                                                {

                                                      BldVerLinkIsToWrongFile = true;

                                                }

                                                else

                                                {

                                                      foundBldVerLink = true;

                                                }

 

                                                break;

                                          }

                                          else

                                          {

                                                /* Identity should always exist - this is really unexpected */

                                                EmitMessageFromResx(NoiseLevel.Error, "MISSINGIDENTITY", null, null);

                                                break;

                                          }

                                    }

                              }

                        }

                        else

                        {

                              /* the file is not a link.  Make sure its not

                               * not a copy of BldVer.cs instead of a link.

                               * It is not valid for any other file to be

                               * named BldVer.cs

                               */

                              string identity = ti.GetAttribute("Identity");

                              if (identity != null)

                              {

                                    if (identity.ToLower() == BldVer_File)

                                    {

                                          foundBldVerNotLink = true;

                                          break;

                                    }

                              }

                              else

                              {

                                    /* Identity should always exist - this is really unexpected */

                                    EmitMessageFromResx(NoiseLevel.Error, "MISSINGIDENTITY", null, null);

                                    break;

                              }

                        }

                  }

 

                  if (foundBldVerNotLink)

                  {

                        EmitMessageFromResx(NoiseLevel.Error, "BLDVERNOTLINK", "BLDVERLINK_HINT", "BLDVER_URL");

                  }

                  else if (!foundBldVerLink)

                  {

                        EmitMessageFromResx(NoiseLevel.Error, "BLDVERLINKNOTFOUND", "BLDVERLINK_HINT", "BLDVER_URL");

                  }

                  else if (!foundBldVerLinkSubtypeCode)

                  {

                        EmitMessageFromResx(NoiseLevel.Error, "BLDVERWRONGSUBTYPE", "BLDVERWRONGSUBTYPE_HINT", "BLDVER_URL");

                  }

                  else if (BldVerLinkIsToWrongFile)

                  {

                        EmitMessageFromResx(NoiseLevel.Error, "BLDVERLINKTOWRONGFILE", "BLDVERLINK_HINT", "BLDVER_URL");

                  }

 

                  return true;

            }

 

            [Required]

            public ITaskItem[] Sources

            {

                  set

                  {

                        foreach (ITaskItem ti in value)

                        {

                              m_sources.Add(ti);

                        }

                  }

            }

      }

}

 

 

 

Posted: Monday, February 16, 2004 1:55 PM by RobertHorvick
Filed under:

Comments

No Comments

New Comments to this post are disabled
Page view tracker