Subbu,

I've been playing with his code a bit myself and
pulled a few bugs out.  It's still failing, but gets
further along.  I'll attach the latest code.  There's
one problem I'm now stumped on but Peter gave me his
advise which I'll paste below (haven't had time to
look into his advise):

I said:

<!------------snip--------------->
Peter,

I've gotten a few bugs worked out of that task, but am
perplexed by what you were doing with one particular
line that crashes:

compileTask.Initialize(null);

It won't accept "null" (compiles but crashes when it
hits the line) and I have no idea what to pass it.  If
I remove this line, the VB6 task errors out with "VB6
didn't start" or something like that.  Any clue?

Thanks,
Eric

<!----------end snip------------->

Peter said:

<!------------snip--------------->
Eric,

I traced it back to Element.cs which takes an XmlNode.

This should probably be the configuration for the
task, or at least a default XmlNode!

The base class calls InitializeElement in the derived
class. 

XmlNode is in System.Xml I think. At the very worst,
you should be able to parse a string with the a simple
vb6task call from a nant build file and pass the
parsed XmlNode to it. The question I see is whether
anything from that XmlNode is actually used. If you
pass a sensible vb6task xml fragment to it that has no
filesets defined then Vb6Task should be able to grab
any configuration it needs without crashing.

Hope that works for you,

Peter

<!----------end snip------------->

I'll keep working at it when I have time, but I too,
am spread very thin.

Thanks,
Eric


--- Subbu Balakrishnan
<[EMAIL PROTECTED]> wrote:

> Hi Christian
> 
> Talk about being spread thin on the ground! Similar
> situation here which is
> why I went all quiet. I hope you are able to get
> through the database side
> of things in short order. I have been reading
> through Peter's code on the
> train ride in and it comes very close to fulfilling
> my needs - I'll need to
> make a few changes though. Having managed to "get my
> hands" on the important
> bits (thanks Peter/Els/John) it would be unfortunate
> if I didn't do
> something to address my particular requirement -
> there goes my weekend! I'll
> keep you informed on any progress I make. I will
> also look at how we can
> fold your IDL generation requirement into this.
> 
> Personally, I think its great you've gone the IDL
> route - I have been burnt
> by Binary Compatibility issues often enough to
> appreciate this.
> 
> Regards
> Subbu 
> 
> -----Original Message-----
> From: Crowhurst,Christian
> [mailto:[EMAIL PROTECTED]
> Sent: Tuesday, 2 November 2004 6:45 PM
> To: Subbu Balakrishnan
> Cc: [EMAIL PROTECTED]
> Subject: RE: [Nant-users] VB6 build dependencies
> 
> 
> Hi Subbu,
> 
> Yeah I agree it was generous of these guys to supply
> the code.
> 
> As to my progress on getting the build to work. My
> time is torn between
> trying to include SQL Server databases in the
> automated build, test and
> deploy cycle and getting the vb6 build to work
> without having to hard wire a
> dependency order into the scripts. As you can
> imagine I'm being spread
> somewhat thinly! The database side of things is
> become more painful by the
> day so I've had to prioritise this and leave the vb6
> build hard-wired.
> 
> With the vb6 problem I've also got the problem of
> "compiling" IDL files to
> add to the mix. We use the IDL to create custom
> interfaces (contained in
> type libraries) that our vb6 classes implement. I've
> got to make sure these
> are compiled in the dependency order along with the
> vb6 code that implements
> them. All told the whole lot feels somewhat
> daunting. But hey life would be
> boring if there wasn't a challenge or two along the
> way, right? ;-)
> 
> Christian
> 
> 
> 
> -----Original Message-----
> From: Subbu Balakrishnan
> [mailto:[EMAIL PROTECTED]
> Sent: 02 November 2004 05:21
> To: '[EMAIL PROTECTED]'; '[EMAIL PROTECTED]';
> Crowhurst,Christian
> Cc: '[EMAIL PROTECTED]';
> '[EMAIL PROTECTED]'
> Subject: Re: [Nant-users] VB6 build dependencies
> 
> 
> 
> Quite by accident, I came upon the John's
> vbp.build.include and Els'
> (Peter's?) C# code to create a build order. Gents,
> can't thank you enough.
> I've had some trouble getting started with this and
> these two pieces of code
> will be an immense help.
> 
> Christian, any joy with your vb6 build issues?
> 
> Regards
> Subbu
> 
> 
> 
> 
>
-------------------------------------------------------
> This SF.Net email is sponsored by:
> Sybase ASE Linux Express Edition - download now for
> FREE
> LinuxWorld Reader's Choice Award Winner for best
> database on Linux.
>
http://ads.osdn.com/?ad_id=5588&alloc_id=12065&op=click
> _______________________________________________
> Nant-users mailing list
> [EMAIL PROTECTED]
>
https://lists.sourceforge.net/lists/listinfo/nant-users
> 
> 
> Click
>
https://www.mailcontrol.com/sr/Gb0TFaJaw3UpCRoMIAzzsW9ag8oN+4dVsoQcg3j82JopL
>
11Xm!+o2nW+XZfOrktxXto2pepsmb6tB7RfuiQ17kkHCkXLAafy3GS0Np2v5mJc!SUE1LVuo!7vT
>
GV7pANBgzsFAHTUd+TfW7GtXj1xx!8Y5Vx8QGcAgQY00opkr56lCKv0gGhbsna0ozBmk9aUpGxW!
> J0V7ogwrf9kiU7!n5kJMUo1!iGP+O35zr1sble0hIPIBasuGg== 
> to report this email as
> spam. 
>   
>   
> This e-mail, and any attachment, is confidential and
> is intended only for
> the use of the individual to which it is addressed.
> If you have received it
> in error, please delete it from your system, do not
> use or disclose the
> information in any way. The contents of this message
> may contain personal
> views which are not the views of the ECA Group,
> unless specifically stated. 
>  
> 
> 
>
-------------------------------------------------------
> This SF.Net email is sponsored by:
> Sybase ASE Linux Express Edition - download now for
> FREE
> LinuxWorld Reader's Choice Award Winner for best
> database on Linux.
>
http://ads.osdn.com/?ad_id=5588&alloc_id=12065&op=click
> _______________________________________________
> NAntContrib-Developer mailing list
> [EMAIL PROTECTED]
>
https://lists.sourceforge.net/lists/listinfo/nantcontrib-developer
> 



                
__________________________________ 
Do you Yahoo!? 
Check out the new Yahoo! Front Page. 
www.yahoo.com 
 
//
// NAntContrib
// Copyright (C) 2001-2003 Gerry Shaw
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
//
// Eric Fetzer ([EMAIL PROTECTED])
// Peter A. Horsfield ([EMAIL PROTECTED])

using System;
using System.Collections.Specialized; 
using System.Collections;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;

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

namespace NAnt.Contrib.Tasks {
        /// <summary>
        /// Compiles multiple dependent Microsoft Visual Basic 6 projects.
        /// </summary>
        /// <remarks>
        ///     <para>Uses the <see cref="Vb6Task">VB6 Task</see> to perform the 
actual compile.</para>
        /// </remarks>
        /// <example>
        ///   <para>Build all projects found under the <c>vbproject</c> 
directory.</para>
        ///   <code>
        ///     <![CDATA[
        /// <vb6tree>
        ///    <source basedir="vbproject">
        ///        <includes name="**.vbp"></includes>
        ///    </source>
        ///    <references>
        ///         <includes name="c:\Program Files\Microsoft Office\Office10\**.dll" 
/>
        ///    </references>
        /// </vb6tree>
        ///     ]]>
        ///   </code>
        /// </example>

                public class VBRef 
                {
                        public string _clsid;
                        public int _usageCount = 1;
                        public string ver;
                        public string tmp;
                        public string path;
                        public string name;
            public System.Collections.Specialized.StringCollection _searchResults = 
null;
                        
                        public void Parse(string p) 
                        {
                                string[] refData = p.Split(new char[] {'#'},5);
                                _clsid = refData[0];
                                ver=refData[1];
                                tmp=refData[2];
                                path=refData[3];
                                name=refData[4];
                        }
                };

                public class VBProj
                {
                        public string filename;
                        public enum STATE { NOTDONE = 0, INPROCESS = 1, DONE=2 };
                        public STATE _done = STATE.NOTDONE;
                        public bool _buildSucceeded = false;
                        public string _shortName;
                        public string _dir;
                        public string _outputFile;
                        public string _title;
                        public ArrayList _references = new ArrayList();
                        public ArrayList _projectDependencies = new ArrayList();
                        public ArrayList _refsWithoutProj = new ArrayList();
                        public ArrayList _refsInPath = new ArrayList();

                        public void Parse(string fname)
                        {
                                filename = fname;

                                FileInfo fdata = new FileInfo(filename);               
                 

                                _dir = fdata.DirectoryName;                     
                                _shortName = fdata.Name;

                                System.IO.FileStream fstr = 
fdata.Open(System.IO.FileMode.Open,FileAccess.Read);
                                System.IO.StreamReader srdr = new StreamReader(fstr);
                                
                                string prop;
                                
                                while(null!=(prop = srdr.ReadLine())) 
                                {                                       
                                        string[] pair = prop.Split(new char[] {'='},2);
                                        switch(pair[0])
                                        {
                                                case "Reference": 
                                                        VBRef vbref = new VBRef();
                                                        vbref.Parse(pair[1]);
                                                    _references.Add(vbref);
                                                        break;
                                                case "Title": 
                                                        _title = pair[1]; 
                                                        break;
                                                case "ExeName32":
                                                        _outputFile = pair[1].Trim(new 
char[] { '\"' }); 
                                                        break;
                                        }
                                }
                                fstr.Close();                           
                        }

            public string FileContents 
            {
                get 
                { 
                    StreamReader prjFileReader = null;
                    FileStream prjFileStream = null;
                    try 
                    {
                        prjFileReader = new StreamReader(prjFileStream = 
File.Open(filename,FileMode.Open));    
                        return prjFileReader.ReadToEnd();
                    }
                    finally
                    {
                        if(null != prjFileStream)
                        {
                            prjFileStream.Close();
                        }
                        if(null != prjFileReader)
                        {
                            prjFileReader.Close();
                        }
                    }
                }
            }
                };


    [TaskName("vb6tree")]
    public class Vb6TreeBuilder : NAnt.Core.Task {
        
        private FileSet     _source = new FileSet();
        private bool        _traceOnly = false;
        private Hashtable   _refsWithoutProj = new Hashtable();
        private FileSet     _references = new FileSet();
        private FileInfo     _errorFile = null;

        /// <summary>
        /// Set of vb base.Project / group files to use as input
        /// </summary>
        [BuildElement("source")]
        public FileSet Source
        {
            get { return _source; }
            set { _source = value; }
        }

        /// <summary>
        /// Set of files that can be considered references
        /// </summary>
        [BuildElement("references")]
        public FileSet References 
        {
            get { return _references; }
            set { _references = value; }
        }

        /// <summary>
        /// The file to which the Visual Basic compiler should log errors.
        /// Forwarded on to the VB6 compiler
        /// </summary>
        [TaskAttribute("errorfile")]
        public FileInfo ErrorFile 
        {
            get { return _errorFile; }
            set { _errorFile = value; }
        } 

        [TaskAttribute("traceOnly")]
        [BooleanValidator()]
        public bool TraceOnly 
        {
            get { return _traceOnly; }
            set { _traceOnly = value; }
        }         

        ///<summary>
        ///Initializes task and ensures the supplied attributes are valid.
        ///</summary>
        ///<param name="taskNode">Xml node used to define this task instance.</param>
        protected override void InitializeTask(System.Xml.XmlNode taskNode) 
        {
                        base.InitializeTask(taskNode);

            if (_source.FileNames.Count == 0) 
            {
                throw new BuildException("base.Projects fileset cannot be empty!", 
Location);
            }
        }

        #region Logger Helper Methods (LogInfo,LogError,LogWarning,LogVerbose,LogDebug)
        private void LogInfo(string msg, params Object[] objs)
        {
            base.Project.Log(Level.Info,msg,objs);
        }
        private void LogError(string msg, params Object[] objs)
        {
            base.Project.Log(Level.Error,msg,objs);
        }
        private void LogWarning(string msg, params Object[] objs)
        {
            base.Project.Log(Level.Warning,msg,objs);
        }
        private void LogDebug(string msg, params Object[] objs)
        {
            base.Project.Log(Level.Debug,msg,objs);
        }
        private void LogVerbose(string msg, params Object[] objs)
        {
            base.Project.Log(Level.Verbose,msg,objs);
        }
        #endregion Logger Helper Methods 
(LogInfo,LogError,LogWarning,LogVerbose,LogDebug)

        /// <summary>
        /// Builds a map of projects to possible outputs before traversing them.
        /// </summary>
        protected override void ExecuteTask() 
        {                                    
            
//Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#..\..\..\WINNT\System32\stdole2.tlb#OLE
 Automation
            //Title="Adapter"
            //ExeName32="Adapter.dll"

            Hashtable outputToProject = new Hashtable();
            Hashtable vbpsInMemory = new Hashtable();

            foreach(string filename in _source.FileNames)
            {
                VBProj proj = new VBProj();
                proj.Parse(filename);

                outputToProject[proj._shortName] = proj;

                                string temp = 
proj._outputFile.Substring(0,proj._outputFile.LastIndexOf("."));
                         
                outputToProject[temp+".tlb"] = proj;
                outputToProject[temp+".vbp"] = proj;
                outputToProject[temp] = proj;
                                
            }

            LogInfo("{0} base.Projects loaded into memory", _source.FileNames.Count);

            foreach(VBProj prj in outputToProject.Values)
            {
                if(prj._done == VBProj.STATE.NOTDONE)RecurseOver("[vb6r] ", prj, 
outputToProject);
            }

            if(_refsWithoutProj.Values.Count > 0)
            {
                LogWarning("References problems:");
            }
            foreach(VBRef vbref in _refsWithoutProj.Values)
            {
                string searchpath = 
vbref.path.Substring(vbref.path.LastIndexOf("\\")+1);
                                
                System.Collections.Specialized.StringCollection pc = 
vbref._searchResults;
                        
                if(pc.Count == 0)
                {                                       
                    string cleared = vbref.path.Replace("..\\","");
                    LogError("   * {0}, used by {1} base.Projects", cleared, 
vbref._usageCount);
                }
                else
                {                                       
                    LogVerbose("   . {0} => ", searchpath);
                }
                                
                foreach(string s in pc)
                {
                    LogVerbose("   ... {0}", s);
                }
                                
            }

        }

        ///<summary>
        ///Builds the given project. If the project has dependencies, it builds those 
first.
        ///</summary>
        ///<param name="pfx">A log prefix used to indent log output.</param>
        ///<param name="prj">The VB project to be built.</param>
        ///<param name="outputToProject">A mapping of output files (reference targets) 
to projects previously built.</param>
        private bool RecurseOver(string pfx, VBProj prj, System.Collections.Hashtable 
outputToProject)
        {
            string logRefsInPath="";
            string logRefsNotFound = "";
                        
            // Check the state of the project we have been asked to build:

            switch(prj._done)
            {
                case VBProj.STATE.INPROCESS:
                    // This project is a dependency of itself :(
                    LogError(pfx + "{0} CIRCULAR REFERENCE!", prj._shortName);
                    return false;
                case VBProj.STATE.DONE:
                    // This project has already been built
                    LogVerbose(pfx + "{0} {1}", prj._shortName,prj._buildSucceeded ? 
"DONE" : "PREVIOUSLY FAILED" );
                    return true;
            }

            // Mark project in process being built
            prj._done = VBProj.STATE.INPROCESS;
                        
            int countOfValidRefs = 0;

            // Build dependencies first by mapping references 
            // to the projects that create them
            LogInfo(pfx + "{0} checking...", prj._shortName);
            foreach(VBRef vbref in prj._references)
            {
                string relative = vbref.path;

                relative = relative.Replace(".dll","");
                relative = relative.Replace(".tlb","");
                relative = relative.Replace(".exe","");

                string _shortName = relative.Substring(relative.LastIndexOf("\\")+1);
                                
                switch(outputToProject.ContainsKey(_shortName))
                {
                    case true: 
                        // This reference has a matching project

                        LogDebug(pfx + "| Ref ({0})", 
((VBProj)outputToProject[_shortName])._outputFile);
                        
prj._projectDependencies.Add(((VBProj)outputToProject[_shortName]));
                        if(RecurseOver(pfx+"| ", 
((VBProj)outputToProject[_shortName]), outputToProject))
                        {
                            ++countOfValidRefs;
                        }
                                                
                        break;
                    case false: 
                        // This reference is not part of the project collection
                        // So we search for it:

                        VBRef prevRef = (VBRef)_refsWithoutProj[vbref._clsid];
                        System.Collections.Specialized.StringCollection searchResults 
= null;
                                                             
                        if(prevRef != null)
                        {
                            // Reference has previously been searched for
                            searchResults = prevRef._searchResults;
                        }
                        else prevRef = vbref;
                                                
                        string searchpath = 
prevRef.path.Substring(prevRef.path.LastIndexOf("\\")+1);
                                                
                        // Perform search, if necessary
                        if(searchResults == null)
                        {
                            NAnt.Core.PathScanner p = new NAnt.Core.PathScanner();
                            p.Add(searchpath);
                                                    
                            searchResults = p.Scan();
                            prevRef._searchResults = searchResults;
                        }                                        
                        
                        // Analyze results
                        if(searchResults.Count == 0)
                        {
                            // Mark not found in project
                            prj._refsWithoutProj.Add(vbref);
                                                        
                                                        // Similarly mark in the 
global list of lost projects
                                                        
if(!_refsWithoutProj.ContainsKey(vbref._clsid))
                                                        {
                                                                
_refsWithoutProj.Add(vbref._clsid,vbref);
                                                        }
                                                        else
                                                        {
                                                                // Increment # of 
projects using for kicks
                                                                ++prevRef._usageCount;
                                                        }
                        }
                        else 
                        {
                            // Mark found via search in project
                            prj._refsInPath.Add(vbref);
                        }
                                                
                        // We're done now, but build a log message for information only
                        string cleared = prevRef.path.Replace("..\\","");
                        string _shortName2 = 
searchpath.Substring(searchpath.LastIndexOf("\\")+1);
                                                   
                        if(searchResults.Count == 0)
                        {                       
                            logRefsNotFound += _shortName2 + ", ";
                        }
                        else
                        {                                       
                            logRefsInPath += _shortName2 + "(";
                        }
                                                
                        foreach(string s in searchResults)
                        {
                            LogDebug(pfx+"| {2} alt: {0} for {1}", s,searchpath, 
prj._shortName);
                            logRefsInPath += s;
                            logRefsInPath += ", ";
                        }
                                                
                        if(searchResults.Count != 0)
                        {                                       
                            logRefsInPath += ")";
                        }

                        break;
                }
            }
            
            // Log results
            if(prj._refsInPath.Count > 0) LogVerbose(pfx + "| {0} IN PATH {1}", 
prj._shortName, logRefsInPath);
            if(prj._refsWithoutProj.Count > 0) LogVerbose(pfx + "| {0} MISSING {1}", 
prj._shortName, logRefsNotFound);
                        
            if(prj._refsWithoutProj.Count == 0 && prj._refsInPath.Count + 
countOfValidRefs == prj._references.Count ) 
            {
                // Finally, invoke the Vb6 task to build this project.

                try 
                {
                    BuildProject(prj);


                    LogInfo(pfx + "{0} OK!",prj._shortName);

                    
                    return prj._buildSucceeded=true;
                }
                finally 
                {
                    // Project has been built
                    prj._done = VBProj.STATE.DONE;                    
                }                
            }
            else 
            {                   
                LogError(pfx + "{0} MISSING REFERENCES {1}/{2}/{3}!",prj._shortName, 
countOfValidRefs, prj._references.Count-prj._refsWithoutProj.Count, 
prj._references.Count);
                
                // Project cannot be built
                prj._done = VBProj.STATE.DONE;

                return prj._buildSucceeded=false; 
            }
        }
/// <summary>
/// Rewrites a project file for a project and then compiles it. 
/// This rewritten version includes modifying references to point 
/// to their resolved locations.
/// </summary>
/// <param name="prj">The Visual Basic project to compile</param>
        protected void BuildProject(VBProj prj)
        {
            FileInfo projectFileInfo = new FileInfo(prj.filename);
            FileInfo tempProjectFileInfo = new FileInfo(projectFileInfo.DirectoryName 
+ @"\tmp_" + prj._shortName);
            FileInfo outputFileInfo = new FileInfo(prj._outputFile);
                        
System.IO.File.Copy(prj.filename,tempProjectFileInfo.FullName,true);

                        try 
                        {
                                Vb6Task compileTask = new Vb6Task();
                                compileTask.CheckReferences=true;
                                compileTask.ErrorFile = ErrorFile;
                                compileTask.OutDir = outputFileInfo.Directory;
                                compileTask.Project = base.Project;
                                compileTask.ProjectFile = tempProjectFileInfo;         
   
                                if(!TraceOnly)
                                {
                                        compileTask.Execute();
                                }
                        }
                                
                        catch(System.Exception ex)
                        {
                                Console.WriteLine("Error is: " + ex.Message);
                        }
                        finally
                        {

                                tempProjectFileInfo.Delete();

                        }

            //-------------------------------------------------            
        }
    }
}

Reply via email to