I had a couple of requests for the code I used to build my sql script on the fly in conjunction with NAntContrib (blogged about it here). Before I show the code, my next refactoring would include (1) creating a ProcessState interface and generating seperate ProcessState classes for NAnt and MultiThreaded environments and (2) do the same for vssManager to handle multiple source control engines.
Before I list the code, I suppose I should add a CMA disclaimer:
The code listed below is offered without any warranty expressed or implied. This is despite anything stated before, after or during this posting. To understand the scope of this lack of a warranty, understand that no guarantee is made that code will compile and if it does compile and actually accomplishes anything it is merely a coincidence on par with a monkey randomly banging on a typewriter and producing a word-for-word copy of Hamlet. If you use the code and it causes you any problems, you assume full responsibility for the problems and obsolve the author of any form of responsibility.
I should have been a lawyer... now for the code...
using System;
using System.Collections;
using System.IO;
using SourceSafeTypeLib;
using System.Xml;
namespace hssScriptBuilder
{
public class hssSourceControl
{
public class ProcessState
{
private ArrayList m_alProcessNotes = new ArrayList();
private String m_sCurrentSection;
private String m_sCurrentItem;
private int m_iSectionCount = 0;
private int m_iCurrentSection = 0;
private int m_iItemCount = 0;
private bool m_bStop = false;
private NAnt.Core.Project _nantProject = null;
public NAnt.Core.Project NAntProject
{
get { return _nantProject; }
set { _nantProject = value; }
}
public void Stop( bool bStop )
{
m_bStop = bStop;
}
public bool IsStopped()
{
return m_bStop;
}
public int GetItemCount()
{
lock(this)
return m_iItemCount;
}
public int GetCurrentSectionIndex()
{
lock(this)
return m_iCurrentSection;
}
public int GetSectionCount()
{
lock(this)
return m_iSectionCount;
}
public String GetCurrentSection()
{
lock(this)
return m_sCurrentSection ;
}
public ArrayList GetProcessNotes()
{
ArrayList aList = new ArrayList();
lock(this)
{
IEnumerator oEnum = m_alProcessNotes.GetEnumerator();
while( oEnum.MoveNext() )
aList.Add( oEnum.Current );
m_alProcessNotes.Clear();
}
return aList;
}
public String GetCurrentItem()
{
lock(this)
{
return m_sCurrentItem;
}
}
public void AddItem()
{
lock(this)
m_iItemCount += 1;
}
public void SetSectionCount( int iCount )
{
lock(this)
m_iSectionCount = iCount;
}
public void SetCurrentItem( String sItem )
{
lock(this)
m_sCurrentItem = sItem;
}
public void AddProcessNote( String sNote )
{
lock(this)
m_alProcessNotes.Add( sNote );
if( _nantProject != null )
_nantProject.Log(NAnt.Core.Level.Verbose, " Processing... {0}", sNote );
}
public void SetFatalError( String sNote )
{
lock(this)
m_alProcessNotes.Add( sNote );
if( _nantProject != null )
_nantProject.Log(NAnt.Core.Level.Error, sNote );
}
public void SetCurrentSection( String sSection )
{
lock(this)
{
if (_nantProject != null )
{
_nantProject.Log(NAnt.Core.Level.Info, "Processing Segment ({0} of {1}): {2}", m_iCurrentSection+1, m_iSectionCount ,sSection );
}
m_sCurrentSection = sSection;
m_iCurrentSection += 1;
}
}
}
private class vssManager
{
private const int VSSITEM_PROJECT = 0;
private const int VSSITEM_ITEM = 1;
private StreamWriter m_sw;
private ProcessState m_oProcessState;
public vssManager( StreamWriter sw, ProcessState oProcessState )
{
m_sw = sw;
m_oProcessState = oProcessState;
}
private void ProcessItem( VSSItem item, String sLocalPath )
{
if ( m_oProcessState.IsStopped() )
return;
if( item.IsCheckedOut != 0 )
{
IVSSCheckouts oCO = item.Checkouts;
String sName = "";
if( oCO.Count > 0 )
{
IEnumerator oEnum = oCO.GetEnumerator();
oEnum.MoveNext();
IVSSCheckout oCheck = (IVSSCheckout)oEnum.Current;
sName = " to " + oCheck.Username;
}
m_oProcessState.AddProcessNote( "WARNING: " + item.Name + " is checked out" + sName + ".");
}
String sSpec = System.IO.Path.Combine(sLocalPath, item.Name);
int iFlags = Convert.ToInt32(VSSFlags.VSSFLAG_REPREPLACE) |
Convert.ToInt32(VSSFlags.VSSFLAG_USERRONO);
item.Get(ref sSpec, iFlags);
m_oProcessState.SetCurrentItem(item.Name);
m_oProcessState.AddItem();
using (StreamReader sr = new StreamReader(sSpec))
{
String line;
while(( line = sr.ReadLine()) != null)
m_sw.WriteLine(line);
}
System.IO.File.Delete(sSpec);
}
private void ProcessProject( VSSItem item, String sLocalPath )
{
foreach( VSSItem subItem in item.get_Items(false))
{
if( m_oProcessState.IsStopped() )
return;
if( subItem.Type == VSSITEM_PROJECT )
ProcessProject( subItem, sLocalPath );
else
ProcessItem( subItem, sLocalPath );
}
}
public void ProcessLineItem( VSSDatabase oVssDb, String sPath, String sLocalPath )
{
VSSItem item = oVssDb.get_VSSItem(sPath, false);
if( item.Type == VSSITEM_PROJECT )
ProcessProject( item, sLocalPath);
else
ProcessItem( item, sLocalPath );
}
public static VSSDatabase GetSourceSafeDatabase(XmlDocument oDoc)
{
String sIniPath, sUserName, sPassword;
try
{
XmlNodeList nodeIni = oDoc.SelectNodes("/hssSourceManagerSection/vssConfig");
sIniPath = nodeIni.Item(0).Attributes.GetNamedItem("IniFile").Value;
sUserName = nodeIni.Item(0).Attributes.GetNamedItem("UserName").Value;
sPassword = nodeIni.Item(0).Attributes.GetNamedItem("Password").Value;
}
catch (Exception ex)
{
throw new Exception("Unable to retrieve SourceSafe configuration information from config file.", ex);
}
VSSDatabase oVssDb = new VSSDatabaseClass();
try
{
oVssDb.Open(sIniPath, sUserName, sPassword);
}
catch( Exception ex)
{
throw new Exception("Unable to open SourceSafe Database", ex);
}
return oVssDb;
}
}
private ProcessState m_oProcessState;
private XmlDocument m_oBuildConfig;
private StreamWriter m_sw;
private NAnt.Core.Project m_nantProject;
private String m_sLocalPath;
public ProcessState GetProcessState()
{
return m_oProcessState;
}
public hssSourceControl()
{
m_oProcessState = new ProcessState();
}
public void ProcessSourceProject( XmlDocument oDoc, StreamWriter sw, string sLocalPath, NAnt.Core.Project nantProject )
{
try
{
VSSDatabase oVss = vssManager.GetSourceSafeDatabase(oDoc);
XmlNodeList nodeSubs = oDoc.SelectNodes("/hssSourceManagerSection/hssSourceItem");
vssManager oMgr = new vssManager(sw, m_oProcessState);
m_oProcessState.NAntProject = nantProject;
m_oProcessState.SetSectionCount( nodeSubs.Count );
for( int i = 0; i < nodeSubs.Count; i++)
{
if( m_oProcessState.IsStopped() )
return;
XmlNode xNode = nodeSubs.Item(i);
String sTitle = xNode.Attributes.GetNamedItem("Value", "").Value;
String sPath = xNode.Attributes.GetNamedItem("Path", "").Value;
m_oProcessState.SetCurrentSection(sTitle);
oMgr.ProcessLineItem(oVss, sPath, sLocalPath);
}
}
catch( Exception ex)
{
string sMsg = string.Format("FATAL ERROR: {0}", ex.Message );
m_oProcessState.SetFatalError( sMsg );
}
}
public void SetThreadData( XmlDocument oBuildConfig,
StreamWriter sw,
NAnt.Core.Project nantProject,
String sLocalPath)
{
m_oBuildConfig = oBuildConfig;
m_sw = sw;
m_nantProject = nantProject;
m_sLocalPath = sLocalPath;
}
public void ThreadProc()
{
ProcessSourceProject( m_oBuildConfig, m_sw, m_sLocalPath, m_nantProject );
}
}
}
