Hello,

here is first attempt to implement <msbuild> task for MSBuild interation. To
be a little usable for us, NAnt users, I made it atleast little compatible
with <solution> task. So its not a simple wrapper around msbuild.exe. Mainly
it accept fileset of projects, which msbuild itself do not. Property names
are compatible with solution task as well.

I also implement function to distinguish between vs2003/vs2005 projects, but
I'm not sure if it'd be useful.

For now, I place it to NAnt.DotNet project. Maybe other location is more
appropriate?

No testcases yet, but they should be next step. Let me know, if you like
this approach. More attibutes/element will be needed as well, I think. Ideas
are welcomed :-)

Almost forgot:
you need to add
                        <task name="msbuild">
                            <attribute name="exename">MSBuild</attribute>
                        </task>
to NAnt.exe.config under <framework name="net-2.0">.

Regards,
Martin Aliger

PS: I'll refactor to follow nant's conding standarts lately. Sorry for
inconvenience. This is just a preview...

Note: MSBuild from net 2.0 Beta 2 will not compile solutions from VS2005
final. Took me hour to figure :)
// NAnt - A .NET build tool
// Copyright (C) 2001-2004 Gerry Shaw
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Martin Aliger ([EMAIL PROTECTED])

using System;
using System.IO;
using System.Collections;
using System.Reflection;
using System.Globalization;

using NAnt.Core;
using NAnt.Core.Types;
using NAnt.Core.Attributes;

namespace NAnt.DotNet.Functions
{
        /// <summary>
        /// Functions to return information for MSBuild system.
        /// </summary>
        [FunctionSet("msbuild", "MSBuild")]
        public class MsbuildFunctions : FunctionSetBase 
        {
                #region Public Instance Constructors

                /// <exclude/>
                public MsbuildFunctions(Project project, PropertyDictionary 
properties) : base(project, properties) {}

                #endregion Public Instance Constructors

                #region Public Instance Methods

                /// <summary>
                /// Test whether project is VS2005 project and could be built 
using &lt;msbuild&gt;
                /// </summary>
                /// <param name="project">The name or path of the project file 
(csproj, vbproj, ...).</param>
                /// <returns>
                /// True, if it is msbuild project, False otherwise.
                /// </returns>
                [Function("is-msbuild-project")]
                public bool IsMsbuildProject(string project) 
                {
                        using(StreamReader str = new 
StreamReader(File.Open(project,FileMode.Open,FileAccess.Read,FileShare.ReadWrite)))
                        {
                                System.Xml.XmlDocument doc = new 
System.Xml.XmlDocument();
                                doc.Load(str);
                                string ns = 
doc.NameTable.Get("http://schemas.microsoft.com/developer/msbuild/2003";);
                                return ns!=null;
                        }                       
                }

                #endregion Public Static Methods
        }
}
// NAnt - A .NET build tool
// Copyright (C) 2001-2002 Gerry Shaw
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Martin Aliger ([EMAIL PROTECTED])

using System;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using System.Text;
using System.Collections;
using System.Collections.Specialized;
using System.CodeDom.Compiler;

using NAnt.Core;
using NAnt.Core.Tasks;
using NAnt.Core.Attributes;
using NAnt.Core.Types;
using NAnt.Core.Util;

using NAnt.DotNet.Types;


namespace NAnt.DotNet.Tasks 
{
        //TODO: write documentation
    /// <summary>
    /// Runs MSBuild system.
    /// </summary>
    /// <remarks>
    /// <note>    
    /// </note>
    /// </remarks>
    /// <example>
        /// </example>
    [TaskName("msbuild")]
    [ProgramLocation(LocationType.FrameworkDir)]
    public class MsbuildTask : ExternalProgramBase {
        #region Private Instance Fields

                private StringBuilder _arguments = null;
                private FileSet _projects = new FileSet();
                private FileInfo _solutionFile;
                private string _configuration;
                private DirectoryInfo _outputDir;

        #endregion Private Instance Fields

        #region Private Static Fields

        #endregion Private Static Fields

        #region Public Instance Properties

                /// <summary>
                /// The projects to build.
                /// </summary>
                [BuildElement("projects", Required=false)]
                public FileSet Projects
                {
                        get { return _projects; }
                        set { _projects = value; }
                }

                /// <summary>
                /// The name of the VS.NET solution file to build.
                /// </summary>
                /// <remarks>
                /// <para>
                /// The <see cref="Projects" /> can be used instead to supply a 
list 
                /// of Visual Studio.NET projects that should be built.
                /// </para>
                /// </remarks>
                [TaskAttribute("solutionfile", Required=false)]
                public FileInfo SolutionFile 
                {
                        get { return _solutionFile; }
                        set { _solutionFile = value; }
                }

                /// <summary>
                /// The name of the solution configuration to build.
                /// </summary>
                /// <remarks>
                /// <para>
                /// Generally <c>release</c> or <c>debug</c>.  Not 
case-sensitive.
                /// </para>
                /// </remarks>
                [TaskAttribute("configuration", Required=false)] //changed to 
non-required
                [StringValidator(AllowEmpty=false)]
                public string Configuration 
                {
                        get { return _configuration; }
                        set { _configuration = 
StringUtils.ConvertEmptyToNull(value); }
                }

        #endregion Public Instance Properties

        #region Override implementation of ExternalProgramBase

                /// <summary>
                /// Gets the command line arguments for the external program.
                /// </summary>
                /// <value>
                /// The command line arguments for the external program.
                /// </value>
                public override string ProgramArguments 
                { 
                        get { return _arguments.ToString(); } 
                }

                /// <summary>
                /// The directory where compiled targets will be placed.  This
                /// overrides path settings contained in the solution/project.
                /// </summary>
                [TaskAttribute("outputdir", Required=false)]
                public DirectoryInfo OutputDir 
                {
                        get { return _outputDir; }
                        set { _outputDir = value; }
                }

                /// <summary>
                /// Starts the external process and captures its output.
                /// </summary>
                protected override void ExecuteTask() 
                {
                        Log(Level.Info, "Starting VS2005 solution build.");

                        FileInfo l_solution = null;

                        using (TempFileCollection tfc = new 
TempFileCollection()) 
                        {

                                if (SolutionFile != null) 
                                {
                                        if (!SolutionFile.Exists) 
                                        {
                                                throw new 
BuildException(string.Format(CultureInfo.InvariantCulture,
                                                        "Couldn't find solution 
file '{0}'.", SolutionFile.FullName), 
                                                        Location);
                                        }
                                        l_solution = SolutionFile;
                                }

                                if (Projects.FileNames.Count > 0) 
                                {
                                        if(l_solution!=null)
                                        {
                                                throw new 
BuildException(string.Format(CultureInfo.InvariantCulture,
                                                        "Both solution and 
projects are specified. Specify just one of those"),
                                                        Location);
                                        }

                                        Log(Level.Verbose, "Included projects:" 
);
                                        foreach (string projectFile in 
Projects.FileNames) 
                                        {
                                                Log(Level.Verbose, " - " + 
projectFile);
                                        }
                                        Log(Level.Verbose, "Creating temporary 
solution to hold all projects.");
                                        
l_solution=CreateTempSolution(tfc,Projects.FileNames);
                                }

                                _arguments=new StringBuilder();
                                _arguments.Append( "/nologo ");
                                //_arguments.Append( "/noconsolelogger ");

                                if (!Verbose) 
                                {
                                        _arguments.Append("/verbosity:normal ");
                                }
                                else
                                {
                                        _arguments.Append("/verbosity:detailed 
"); //diagnostic
                                }

                                if(_outputDir!=null)
                                {
                                        
_arguments.Append("/property:OutDir=\"").Append(_outputDir.FullName).Append("\" 
");
                                }
                                if(_configuration!=null)
                                {
                                        
_arguments.Append("/property:Configuration=").Append(_configuration).Append(" 
");
                                }

                                
_arguments.Append("\"").Append(l_solution.FullName).Append("\" ");

                                Log(Level.Info, "Starting MSBuild");
                                base.ExecuteTask();
                        }
                }

        #endregion Override implementation of ExternalProgramBase

                #region Internal Instance Methods

                private string ReadProjectGuid(string project)
                {
                        using(StreamReader str = new 
StreamReader(File.Open(project,FileMode.Open,FileAccess.Read,FileShare.ReadWrite)))
                        {
                                System.Xml.XmlDocument doc = new 
System.Xml.XmlDocument();
                                doc.Load(str);
                                System.Xml.XmlNamespaceManager nsmgr = new 
System.Xml.XmlNamespaceManager(doc.NameTable);
                                
nsmgr.AddNamespace("vs2005","http://schemas.microsoft.com/developer/msbuild/2003";);
                                System.Xml.XmlNode node = 
doc.SelectSingleNode("//vs2005:ProjectGuid",nsmgr);
                                if(node==null)
                                        throw new 
BuildException(string.Format(CultureInfo.InvariantCulture,
                                                "Unable to read ProjectGuid 
from project '{0}'.", project), 
                                                Location);
                                return node.InnerText;
                        }                       
                }

                private FileInfo CreateTempSolution(TempFileCollection tfc, 
StringCollection projects)
                {
                        string tempFile = tfc.AddExtension("sln",false);
                        using(StreamWriter str = File.CreateText(tempFile))
                        {
                                str.WriteLine("Microsoft Visual Studio Solution 
File, Format Version 9.00");
                                str.WriteLine("# NAnt generated");

                                string solguid = Guid.NewGuid().ToString("B");
                                Hashtable l_projects = new Hashtable();
                                foreach(string project in projects)
                                {
                                        string pg = ReadProjectGuid(project);
                                        l_projects[project]=pg;
                                        str.WriteLine("Project(\"{0}\") = 
\"{3}\", \"{2}\", \"{1}\"",
                                                
solguid,pg,project,Path.GetFileNameWithoutExtension(project));
                                        str.WriteLine("EndProject");
                                }

                                str.WriteLine("Global");
                                
str.WriteLine("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
                                str.WriteLine("\t\tDebug|Any CPU = Debug|Any 
CPU");
                                str.WriteLine("\t\tRelease|Any CPU = 
Release|Any CPU");
                                str.WriteLine("\tEndGlobalSection");
                                
str.WriteLine("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
                                foreach(string project in projects)
                                {
                                        string pg = (string)l_projects[project];
                                        str.WriteLine("\t\t{0}.Debug|Any 
CPU.ActiveCfg = Debug|Any CPU",pg);
                                        str.WriteLine("\t\t{0}.Debug|Any 
CPU.Build.0 = Debug|Any CPU",pg);
                                        str.WriteLine("\t\t{0}.Release|Any 
CPU.ActiveCfg = Release|Any CPU",pg);
                                        str.WriteLine("\t\t{0}.Release|Any 
CPU.Build.0 = Release|Any CPU",pg);
                                }
                                str.WriteLine("EndGlobalSection");
                        }
                        return new FileInfo(tempFile);
                }

                #endregion Internal Instance Methods

    }
}

Reply via email to