#Region " Assembly References " Imports System Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper Imports Microsoft.SqlServer.Dts.Pipeline Imports Microsoft.SqlServer.Dts.Runtime Imports Microsoft.SqlServer.Dts.Runtime.Wrapper Imports Gww.Vss.CommonLibrary #End Region Namespace Gww Namespace Dts Namespace Pipline #Region " Component Class Attribute " _ Public Class VssSourceAdapter Inherits PipelineComponent #Region " Global Constants " Private Const C_USERNAME As String = "SourceSafeLogin" Private Const C_PASSWORD As String = "SourceSafePassword" Private Const C_INIPATH As String = "SourceSafeIniPath" Private Const C_VSSPROJ As String = "SourceSafeProjectPath" Private Const C_LOCAL As String = "LocalFolder" Private Const C_LABEL As String = "SourceSafeItemLabel" Private Const C_DOWNLOAD As String = "SourceSafeFileDownload" Private Const C_RECURSIVE As String = "SourceSafeRecursive" Private m_FilePathColumnIndex As Int16 #End Region #Region " Enumerations " Private Enum TrueFalseValues [False] = 0 [True] = 1 End Enum Private Enum EnableDisableValues Disable = 0 Enable = 1 End Enum #End Region #Region " Design-time Component Methods " Public Overrides Sub ProvideComponentProperties() ' // The ProvideComponentProperties() method provides initialisation of the ' // the component when the component is first added to the Data Flow designer. ' // Support Resetting the Component Call ReinitializeMetaData() ' // Add Custom Properties Dim SecurityName As IDTSCustomProperty90 = ComponentMetaData.CustomPropertyCollection.[New]() SecurityName.Name = C_USERNAME SecurityName.Description = "Enter the username for SourceSafe access." Dim SecurityPwd As IDTSCustomProperty90 = ComponentMetaData.CustomPropertyCollection.[New]() SecurityPwd.Name = C_PASSWORD SecurityPwd.Description = "Enter the password for SourceSafe access." SecurityPwd.EncryptionRequired = True Dim SourceSafeIni As IDTSCustomProperty90 = ComponentMetaData.CustomPropertyCollection.[New]() SourceSafeIni.Name = C_INIPATH SourceSafeIni.Description = "Enter the full path to the SourceSafe Ini file, eg. \\\\..\srcsafe.ini" Dim SourceSafeProj As IDTSCustomProperty90 = ComponentMetaData.CustomPropertyCollection.[New]() SourceSafeProj.Name = C_VSSPROJ SourceSafeProj.Description = "Enter the full path to the SourceSafe Project, eg. $//../" Dim SourceSafeLocal As IDTSCustomProperty90 = ComponentMetaData.CustomPropertyCollection.[New]() SourceSafeLocal.Name = C_LOCAL SourceSafeLocal.Description = "Enter the full path to the Local Working Folder, eg. C:\Temp\" Dim SourceSafeLabel As IDTSCustomProperty90 = ComponentMetaData.CustomPropertyCollection.[New]() SourceSafeLabel.Name = C_LABEL SourceSafeLabel.Description = "Enter the required SourceSafe Item Label (Leave as blank for most recent). The label is case sensitive!" Dim DisableFileDownload As IDTSCustomProperty90 = ComponentMetaData.CustomPropertyCollection.[New]() DisableFileDownload.Name = C_DOWNLOAD DisableFileDownload.Description = "When set to 'disable' the SourceSafe items will not be downloaded to the specified local working folder." DisableFileDownload.TypeConverter = GetType(EnableDisableValues).AssemblyQualifiedName Dim IsRecursive As IDTSCustomProperty90 = ComponentMetaData.CustomPropertyCollection.[New]() IsRecursive.Name = C_RECURSIVE IsRecursive.Description = "Recursion is the ability to process all sub-folders in SourceSafe. Set to 'true' to enable this functionality." IsRecursive.TypeConverter = GetType(TrueFalseValues).AssemblyQualifiedName End Sub _ Public Overrides Function Validate() As DTSValidationStatus ' // The Validate() function is mostly called during the design-time phase of ' // the component. Its main purpose is to perform validation of the contents of the component. Dim bCancel As Boolean ' // Just in case someone messed around with the xml configuration file! If ComponentMetaData.CustomPropertyCollection.Count <> 9 Then ComponentMetaData.FireError(0, ComponentMetaData.Name, "CustomPropertyCollection does not equal 9 as supported by this component.", "", 0, bCancel) Return DTSValidationStatus.VS_ISCORRUPT End If ' // Need to use VS_ISBROKEN, otherwise the designer would not be user-friendly! If ComponentMetaData.CustomPropertyCollection(C_USERNAME).Value Is Nothing OrElse CType(ComponentMetaData.CustomPropertyCollection(C_USERNAME).Value, String).Length = 0 Then ComponentMetaData.FireError(0, ComponentMetaData.Name, "UserName must be set.", "", 0, bCancel) Return DTSValidationStatus.VS_ISBROKEN End If If ComponentMetaData.CustomPropertyCollection(C_PASSWORD).Value Is Nothing OrElse CType(ComponentMetaData.CustomPropertyCollection(C_PASSWORD).Value, String).Length = 0 Then ComponentMetaData.FireError(0, ComponentMetaData.Name, "Password cannot be blank.", "", 0, bCancel) Return DTSValidationStatus.VS_ISBROKEN End If If ComponentMetaData.CustomPropertyCollection(C_INIPATH).Value Is Nothing OrElse CType(ComponentMetaData.CustomPropertyCollection(C_INIPATH).Value, String).Length = 0 Then ComponentMetaData.FireError(0, ComponentMetaData.Name, "Enter the SourceSafe INI path as \\\\..\srcsafe.ini", "", 0, bCancel) Return DTSValidationStatus.VS_ISBROKEN Elseif Not System.IO.File.Exists(ComponentMetaData.CustomPropertyCollection(C_INIPATH).Value.ToString.Trim) Then ComponentMetaData.FireError(0, ComponentMetaData.Name, String.Format("The SourceSafe INI file '{0}' does not exist or is not accessible!", ComponentMetaData.CustomPropertyCollection(C_INIPATH).Value.ToString.Trim), "", 0, bCancel) Return DTSValidationStatus.VS_ISBROKEN End If If ComponentMetaData.CustomPropertyCollection(C_VSSPROJ).Value Is Nothing OrElse CType(ComponentMetaData.CustomPropertyCollection(C_VSSPROJ).Value, String).Length = 0 Then ComponentMetaData.FireError(0, ComponentMetaData.Name, "Enter the SourceSafe project path as $//../", "", 0, bCancel) Return DTSValidationStatus.VS_ISBROKEN End If If ComponentMetaData.CustomPropertyCollection(C_LOCAL).Value Is Nothing OrElse CType(ComponentMetaData.CustomPropertyCollection(C_LOCAL).Value, String).Length = 0 OrElse Not ComponentMetaData.CustomPropertyCollection(C_LOCAL).Value.ToString.EndsWith("\") Then ComponentMetaData.FireError(0, ComponentMetaData.Name, "Enter the local path as [DRIVE]:\\..\ or \\\\..\", "", 0, bCancel) Return DTSValidationStatus.VS_ISBROKEN ElseIf Not System.IO.Directory.Exists(ComponentMetaData.CustomPropertyCollection(C_LOCAL).Value.ToString.Trim) Then ComponentMetaData.FireError(0, ComponentMetaData.Name, String.Format("The local folder '{0}' does not exist or is not accessible!", ComponentMetaData.CustomPropertyCollection(C_LOCAL).Value.ToString.Trim), "", 0, bCancel) Return DTSValidationStatus.VS_ISBROKEN End If If Not (ComponentMetaData.CustomPropertyCollection(C_LABEL).Value Is Nothing OrElse CType(ComponentMetaData.CustomPropertyCollection(C_LABEL).Value, String).Length = 0) Then If CType(ComponentMetaData.CustomPropertyCollection(C_LABEL).Value, String).Trim.Length > 31 Then ComponentMetaData.FireError(0, ComponentMetaData.Name, "The label cannot be more than 31 characters long!", "", 0, bCancel) Return DTSValidationStatus.VS_ISBROKEN End If End If If ComponentMetaData.CustomPropertyCollection(C_DOWNLOAD).Value Is Nothing OrElse CType(ComponentMetaData.CustomPropertyCollection(C_DOWNLOAD).Value, String).Length = 0 Then ComponentMetaData.FireError(0, ComponentMetaData.Name, "SourceSafe FileDownload setting must be specified.", "", 0, bCancel) Return DTSValidationStatus.VS_ISBROKEN End If If ComponentMetaData.CustomPropertyCollection(C_RECURSIVE).Value Is Nothing OrElse CType(ComponentMetaData.CustomPropertyCollection(C_RECURSIVE).Value, String).Length = 0 Then ComponentMetaData.FireError(0, ComponentMetaData.Name, "SourceSafe Recursive setting must be specified.", "", 0, bCancel) Return DTSValidationStatus.VS_ISBROKEN End If If ComponentMetaData.OutputCollection(0).OutputColumnCollection.Count <> 1 Then Return DTSValidationStatus.VS_ISCORRUPT End If Return MyBase.Validate End Function Public Overrides Sub ReinitializeMetaData() ' // The ReinitializeMetaData() method will be called when the Validate() function returns VS_NEEDSNEWMETADATA. ' // Its primary purpose is to repair the component's metadata to a consistent state. ' // Support Resetting the Component RemoveAllInputsOutputsAndCustomProperties() ComponentMetaData.RuntimeConnectionCollection.RemoveAll() ' // Add an output and configure its output column Dim output As IDTSOutput90 = ComponentMetaData.OutputCollection.[New] output.Name = "Output" output.ExternalMetadataColumnCollection.IsUsed = True Dim outputColumn As IDTSOutputColumn90 = output.OutputColumnCollection.New() outputColumn.Name = "filepath" outputColumn.SetDataTypeProperties(DataType.DT_WSTR, 4000, 0, 0, 0) ' // Map the output column to the external meta data column Me.CreateExternalMetaDataColumn(output, outputColumn) End Sub Public Overrides Sub PerformUpgrade(ByVal pipelineVersion As Integer) ' // Enables updating of an existing version of a component to a newer version ComponentMetaData.CustomPropertyCollection("UserComponentTypeName").Value = Me.GetType().AssemblyQualifiedName End Sub Private Sub CreateExternalMetaDataColumn(ByVal output As IDTSOutput90, ByVal outputColumn As IDTSOutputColumn90) ' // Set the properties of the external metadata column. Dim externalColumn As IDTSExternalMetadataColumn90 = output.ExternalMetadataColumnCollection.New() externalColumn.Name = outputColumn.Name externalColumn.Precision = outputColumn.Precision externalColumn.Length = outputColumn.Length externalColumn.DataType = outputColumn.DataType externalColumn.Scale = outputColumn.Scale ' // Map the external column to the output column. outputColumn.ExternalMetadataColumnID = externalColumn.ID End Sub #End Region #Region " Runtime Component Methods " Public Overrides Sub PreExecute() ' // We have one output buffer defined with a single column Dim output As IDTSOutput90 = ComponentMetaData.OutputCollection(0) m_FilePathColumnIndex = CType(BufferManager.FindColumnByLineageID(output.Buffer, output.OutputColumnCollection(0).LineageID), Integer) End Sub Public Overrides Sub PrimeOutput(ByVal Outputs As Integer, ByVal OutputIDs As Integer(), ByVal Buffers As PipelineBuffer()) ' // This is where all coding is done to utilise the SourceSafe CommonLibrary created sepcifically ' // for this project. Dim buffer As PipelineBuffer = Buffers(0) ' // Create a new instance of the Gww.Vss.CommonLibrary.VssReader object Dim vss As VssReader = New VssReader Try ' // Initialise all object property values vss.Username = ComponentMetaData.CustomPropertyCollection(C_USERNAME).Value vss.Password = ComponentMetaData.CustomPropertyCollection(C_PASSWORD).Value vss.SrcSafeIni = ComponentMetaData.CustomPropertyCollection(C_INIPATH).Value vss.ProjectPath = ComponentMetaData.CustomPropertyCollection(C_VSSPROJ).Value vss.LocalPath = ComponentMetaData.CustomPropertyCollection(C_LOCAL).Value vss.Label = ComponentMetaData.CustomPropertyCollection(C_LABEL).Value vss.FileDownload = ComponentMetaData.CustomPropertyCollection(C_DOWNLOAD).Value vss.IsRecursive = ComponentMetaData.CustomPropertyCollection(C_RECURSIVE).Value ' // Connect to the SourceSafe database If vss.connect() Then ' // Retrieve SourceSafe files based on 'latest version' or on a particular 'label' If vss.getLatest() Then ' // for each file in the collection, output the data to the component's output buffer Dim vFile As String For Each vFile In vss.FileColl() buffer.AddRow() Buffers(0).SetString(m_FilePathColumnIndex, vFile) Next End If End If Catch ex As Exception Err.Raise(65000, ComponentMetaData.Name, ex.Message) Finally ' // clean-up vss.disconnect() buffer.SetEndOfRowset() End Try End Sub #End Region End Class #End Region End Namespace End Namespace End Namespace