Option Compare Database Option Explicit ' List of lookup tables that are part of the program rather than the ' data, to be exported with source code ' Set to "*" to export the contents of all tables 'Only used in ExportAllSource 'Private Const include_tables As String = "" Private include_tables As String ' This is used in ImportAllSource Private Const DebugOutput As Boolean = False 'this is used in ExportAllSource 'Causes the VCS_ and OA_ modules to be exported Private Const ArchiveMyself As Boolean = False 'returns true if named module is NOT part of the VCS / OA code Private Function IsNotVCS(ByVal name As String) As Boolean '*** if OA addin is used from its developement version (OA exporting itself) If CurrentProject.name = "openaccess.accda" Then IsNotVCS = True Exit Function End If '**** If name <> "OA_Controls" And _ name <> "OA_Log" And _ name <> "OA_Main" And _ name <> "OA_Optimizer" And _ name <> "OA_Properties" And _ name <> "OA_Shell" And _ name <> "OA_Utils" And _ name <> "VCS_DataMacro" And _ name <> "VCS_Dir" And _ name <> "VCS_File" And _ name <> "VCS_IE_Functions" And _ name <> "VCS_ImportExport" And _ name <> "VCS_Reference" And _ name <> "VCS_Relation" And _ name <> "VCS_Report" And _ name <> "VCS_String" And _ name <> "VCS_Table" Then IsNotVCS = True Else IsNotVCS = False End If End Function ' Main entry point for EXPORT. Export all forms, reports, queries, ' macros, modules, and lookup tables to `source` folder under the ' database's folder. Public Sub ExportAllSource() Dim Db As Object ' DAO.Database Dim source_path As String Dim obj_path As String Dim qry As Object ' DAO.QueryDef Dim doc As Object ' DAO.Document Dim obj_type As Variant Dim obj_type_split() As String Dim obj_type_label As String Dim obj_type_name As String Dim obj_type_num As Integer Dim obj_count As Integer Dim obj_data_count As Integer Dim ucs2 As Boolean Dim full_path As String logger "ExportAllSource", "INFO", "Begin 'Export all sources'" include_tables = get_include_tables() logger "ExportAllSource", "DEBUG", "Include_tables: " & include_tables logger "ExportAllSource", "DEBUG", "Optimizer on: " & optimizer_activated() logger "ExportAllSource", "DEBUG", "Save project" CurrentProject.Application.RunCommand acCmdSave Set Db = CurrentDb CloseFormsReports 'InitUsingUcs2 source_path = VCS_Dir.ProjectPath() & "source\" logger "ExportAllSource", "DEBUG", "source_path: " & source_path VCS_Dir.MkDirIfNotExist source_path Call ExportProperties(CurrentDb, source_path & "database.properties") obj_path = source_path & "queries\" VCS_Dir.ClearTextFilesFromDir obj_path, "bas" logger "ExportAllSource", "INFO", "Exporting queries..." obj_count = 0 For Each qry In Db.QueryDefs '### 11/10/2016: add optimizer If optimizer_activated() Then If Not needs_export(acQuery, qry.name) > 0 Then logger "ExportProperties", "DEBUG", "Query " & qry.name & " skipped" obj_count = obj_count + 1 GoTo next_qry End If End If '### DoEvents If Left$(qry.name, 1) <> "~" Then full_path = obj_path & VCS_IE_Functions.to_filename(qry.name) & ".bas" VCS_IE_Functions.ExportObject acQuery, qry.name, full_path, VCS_File.UsingUcs2 obj_count = obj_count + 1 End If next_qry: Call SysCmd(4, "Export query: " & obj_count & " on " & Db.QueryDefs.count) Next logger "ExportAllSource", "INFO", "> " & obj_count & " queries exported" logger "ExportAllSource", "INFO", "Sanitize queries..." VCS_IE_Functions.SanitizeTextFiles obj_path, "bas" For Each obj_type In Split( _ "forms|Forms|" & acForm & "," & _ "reports|Reports|" & acReport & "," & _ "macros|Scripts|" & acMacro & "," & _ "modules|Modules|" & acModule _ , "," _ ) obj_type_split = Split(obj_type, "|") obj_type_label = obj_type_split(0) obj_type_name = obj_type_split(1) obj_type_num = val(obj_type_split(2)) obj_path = source_path & obj_type_label & "\" obj_count = 0 'a retirer VCS_Dir.ClearTextFilesFromDir obj_path, "bas" logger "ExportAllSource", "INFO", "Exporting " & obj_type_label & "..." For Each doc In Db.Containers(obj_type_name).Documents '### 11/10/2016: add optimizer If optimizer_activated() Then If Not needs_export(obj_type_num, doc.name) > 0 Then obj_count = obj_count + 1 logger "ExportAllSource", "DEBUG", obj_type_label & " '" & doc.name & " skipped" GoTo next_doc End If End If '### DoEvents If (Left$(doc.name, 1) <> "~") And _ (IsNotVCS(doc.name) Or ArchiveMyself) Then If obj_type_label = "modules" Then ucs2 = False Else ucs2 = VCS_File.UsingUcs2 End If full_path = obj_path & VCS_IE_Functions.to_filename(doc.name) & ".bas" VCS_IE_Functions.ExportObject obj_type_num, doc.name, full_path, ucs2 If obj_type_label = "reports" Then full_path = obj_path & VCS_IE_Functions.to_filename(doc.name) & ".pv" VCS_Report.ExportPrintVars doc.name, obj_path & doc.name & ".pv" End If Call SysCmd(4, "Exporting " & obj_type_label & ": " & obj_count & " on " & Db.Containers(obj_type_name).Documents.count) obj_count = obj_count + 1 End If next_doc: Next logger "ExportAllSource", "INFO", "> " & obj_count & " " & obj_type_label & " exported" If obj_type_label <> "modules" Then logger "ExportAllSource", "INFO", "Sanitizing " & obj_type_label VCS_IE_Functions.SanitizeTextFiles obj_path, "bas" End If Next VCS_Reference.ExportReferences source_path '-------------------------table export------------------------ obj_path = source_path & "tables\" VCS_Dir.MkDirIfNotExist Left$(obj_path, InStrRev(obj_path, "\")) VCS_Dir.ClearTextFilesFromDir obj_path, "txt", True Dim td As DAO.TableDef Dim tds As DAO.TableDefs Set tds = Db.TableDefs obj_type_label = "tbldef" obj_type_name = "Table_Def" obj_type_num = acTable obj_path = source_path & obj_type_label & "\" obj_count = 0 obj_data_count = 0 VCS_Dir.MkDirIfNotExist Left$(obj_path, InStrRev(obj_path, "\")) 'move these into Table and DataMacro modules? ' - We don't want to determin file extentions here - or obj_path either! VCS_Dir.ClearTextFilesFromDir obj_path, "sql" VCS_Dir.ClearTextFilesFromDir obj_path, "xml" VCS_Dir.ClearTextFilesFromDir obj_path, "LNKD" Dim IncludeTablesCol As Collection Set IncludeTablesCol = StrSetToCol(include_tables, ",") logger "ExportAllSource", "INFO", "Exporting " & obj_type_label & "..." Dim update_this_tabledef As Boolean For Each td In tds '### 11/10/2016: add optimizer 'only update the table definition if this is a complete export 'or if the table definition has been modified since last export update_this_tabledef = (Not optimizer_activated() Or needs_export(acTable, td.name) > 0) '### ' This is not a system table ' this is not a temporary table If Left$(td.name, 4) <> "MSys" And _ Left$(td.name, 1) <> "~" Then If Len(td.connect) = 0 Then ' this is not an external table If update_this_tabledef Then VCS_Table.ExportTableDef Db, td, VCS_IE_Functions.to_filename(td.name), obj_path Else logger "ExportAllSource", "DEBUG", "TableDef " & td.name & " skipped" End If If include_tables = "*" Then DoEvents VCS_Table.ExportTableData CStr(td.name), source_path & "tables\" If Len(dir$(source_path & "tables\" & td.name & ".txt")) > 0 Then obj_data_count = obj_data_count + 1 End If ElseIf (Len(Replace(include_tables, " ", vbNullString)) > 0) And include_tables <> "*" Then DoEvents On Error GoTo Err_TableNotFound If InCollection(IncludeTablesCol, td.name) Then VCS_Table.ExportTableData CStr(td.name), source_path & "tables\" obj_data_count = obj_data_count + 1 End If Err_TableNotFound: 'else don't export table data End If Else If update_this_tabledef Then VCS_Table.ExportLinkedTable td.name, obj_path Else logger "ExportAllSource", "DEBUG", "TableDef " & td.name & " skipped" End If End If obj_count = obj_count + 1 Call SysCmd(4, "Export table definition: " & obj_count & " on " & tds.count) End If next_td: Next logger "ExportAllSource", "INFO", "> " & obj_count & " tbldef exported" logger "ExportAllSource", "INFO", "> " & obj_data_count & " table's datas exported" logger "ExportAllSource", "INFO", "Export relations" obj_count = 0 obj_path = source_path & "relations\" VCS_Dir.MkDirIfNotExist Left$(obj_path, InStrRev(obj_path, "\")) VCS_Dir.ClearTextFilesFromDir obj_path, "txt", True Dim aRelation As DAO.Relation For Each aRelation In CurrentDb.Relations ' Exclude relations from system tables and inherited (linked) relations If Not (aRelation.name = "MSysNavPaneGroupsMSysNavPaneGroupToObjects" _ Or aRelation.name = "MSysNavPaneGroupCategoriesMSysNavPaneGroups" _ Or (aRelation.Attributes And DAO.RelationAttributeEnum.dbRelationInherited) = _ DAO.RelationAttributeEnum.dbRelationInherited) Then VCS_Relation.ExportRelation aRelation, obj_path & aRelation.name & ".txt" obj_count = obj_count + 1 End If Next logger "ExportAllSource", "INFO", "> " & obj_count & " relations exported" '### 13/10/2016: add optimizer ' cleans the obsolete files (see CleanDirs in optimizer) If optimizer_activated() Then Call CleanDirs End If '### logger "ExportAllSource", "INFO", "Export done" End Sub ' Main entry point for IMPORT. Import all forms, reports, queries, ' macros, modules, and lookup tables from `source` folder under the ' database's folder. Public Sub ImportAllSource() Dim fso As Object Dim source_path As String Dim obj_path As String Dim obj_type As Variant Dim obj_type_split() As String Dim obj_type_label As String Dim obj_type_num As Integer Dim obj_count As Integer Dim filename As String Dim obj_name As String Dim ucs2 As Boolean logger "ImportAllSource", "INFO", "Begin 'Import all sources'" logger "ImportAllSource", "DEBUG", "Optimizer on: " & optimizer_activated() Set fso = CreateObject("Scripting.FileSystemObject") CloseFormsReports 'InitUsingUcs2 source_path = VCS_Dir.ProjectPath() & "source\" If Not fso.FolderExists(source_path) Then logger "ImportAllSource", "CRITICAL", "No source found at:" & source_path End If Call ImportProperties(CurrentDb, source_path & "database.properties") If Not VCS_Reference.ImportReferences(source_path) Then logger "ImportAllSource", "INFO", "Info: no references file in " & source_path End If obj_path = source_path & "queries\" filename = dir$(obj_path & "*.bas") Dim tempFilePath As String tempFilePath = VCS_File.TempFile() If Len(filename) > 0 Then logger "ImportAllSource", "INFO", "Importing queries..." obj_count = 0 Do Until Len(filename) = 0 DoEvents obj_name = Mid$(filename, 1, InStrRev(filename, ".") - 1) obj_name = VCS_IE_Functions.to_accessname(obj_name) VCS_IE_Functions.ImportObject acQuery, obj_name, obj_path & filename, VCS_File.UsingUcs2 VCS_IE_Functions.ExportObject acQuery, obj_name, tempFilePath, VCS_File.UsingUcs2 VCS_IE_Functions.ImportObject acQuery, obj_name, tempFilePath, VCS_File.UsingUcs2 obj_count = obj_count + 1 filename = dir$() Loop logger "ImportAllSource", "INFO", "> " & obj_count & " queries imported" End If VCS_Dir.DelIfExist tempFilePath ' restore table definitions obj_path = source_path & "tbldef\" filename = dir$(obj_path & "*.sql") If Len(filename) > 0 Then logger "ImportAllSource", "INFO", "Importing TblDefs..." obj_count = 0 Do Until Len(filename) = 0 obj_name = Mid$(filename, 1, InStrRev(filename, ".") - 1) obj_name = VCS_IE_Functions.to_accessname(obj_name) VCS_Table.ImportTableDef CStr(obj_name), obj_path obj_count = obj_count + 1 filename = dir$() Loop logger "ImportAllSource", "INFO", "> " & obj_count & " TblDefs imported" End If ' restore linked tables - we must have access to the remote store to import these! filename = dir$(obj_path & "*.LNKD") If Len(filename) > 0 Then logger "ImportAllSource", "INFO", "Importing Linked TblDefs..." obj_count = 0 Do Until Len(filename) = 0 obj_name = Mid$(filename, 1, InStrRev(filename, ".") - 1) obj_name = VCS_IE_Functions.to_accessname(obj_name) VCS_Table.ImportLinkedTable CStr(obj_name), obj_path obj_count = obj_count + 1 filename = dir$() Loop logger "ImportAllSource", "INFO", "> " & obj_count & " Linked TblDefs imported" End If ' NOW we may load data obj_path = source_path & "tables\" filename = dir$(obj_path & "*.txt") If Len(filename) > 0 Then logger "ImportAllSource", "INFO", "Importing table's data..." obj_count = 0 Do Until Len(filename) = 0 DoEvents obj_name = Mid$(filename, 1, InStrRev(filename, ".") - 1) obj_name = VCS_IE_Functions.to_accessname(obj_name) VCS_Table.ImportTableData CStr(obj_name), obj_path obj_count = obj_count + 1 filename = dir$() Loop logger "ImportAllSource", "INFO", "> " & obj_count & " table's data imported" End If 'load Data Macros - not DRY! obj_path = source_path & "tbldef\" filename = dir$(obj_path & "*.xml") If Len(filename) > 0 Then logger "ImportAllSource", "INFO", "Importing Data Macros..." obj_count = 0 Do Until Len(filename) = 0 DoEvents obj_name = Mid$(filename, 1, InStrRev(filename, ".") - 1) obj_name = VCS_IE_Functions.to_accessname(obj_name) 'VCS_Table.ImportTableData CStr(obj_name), obj_path VCS_DataMacro.ImportDataMacros obj_name, obj_path obj_count = obj_count + 1 filename = dir$() Loop logger "ImportAllSource", "INFO", "> " & obj_count & " DataMacros imported" End If For Each obj_type In Split( _ "forms|" & acForm & "," & _ "reports|" & acReport & "," & _ "macros|" & acMacro & "," & _ "modules|" & acModule _ , "," _ ) obj_type_split = Split(obj_type, "|") obj_type_label = obj_type_split(0) obj_type_num = val(obj_type_split(1)) obj_path = source_path & obj_type_label & "\" filename = dir$(obj_path & "*.bas") If Len(filename) > 0 Then logger "ImportAllSource", "INFO", "Importing " & obj_type_label & "..." obj_count = 0 Do Until Len(filename) = 0 ' DoEvents no good idea! obj_name = Mid$(filename, 1, InStrRev(filename, ".") - 1) obj_name = VCS_IE_Functions.to_accessname(obj_name) If obj_type_label = "modules" Then ucs2 = False Else ucs2 = VCS_File.UsingUcs2 End If If IsNotVCS(obj_name) Then VCS_IE_Functions.ImportObject obj_type_num, obj_name, obj_path & filename, ucs2 obj_count = obj_count + 1 Else If ArchiveMyself Then logger "ImportAllSource", "WARNING", "Module " & obj_name & " could not be updated while running. Ensure latest version is included!" End If End If filename = dir$() Loop logger "ImportAllSource", "INFO", "> " & obj_count & " " & obj_type_label & " imported" End If Next 'import Print Variables logger "ImportAllSource", "INFO", "Importing Print Vars..." obj_count = 0 obj_path = source_path & "reports\" filename = dir$(obj_path & "*.pv") Do Until Len(filename) = 0 DoEvents obj_name = Mid$(filename, 1, InStrRev(filename, ".") - 1) obj_name = VCS_IE_Functions.to_accessname(obj_name) VCS_Report.ImportPrintVars obj_name, obj_path & filename obj_count = obj_count + 1 filename = dir$() Loop logger "ImportAllSource", "INFO", "> " & obj_count & " Print Vars imported" 'import relations logger "ImportAllSource", "INFO", "Importing Relations..." obj_count = 0 obj_path = source_path & "relations\" filename = dir$(obj_path & "*.txt") Do Until Len(filename) = 0 DoEvents VCS_Relation.ImportRelation obj_path & filename obj_count = obj_count + 1 filename = dir$() Loop logger "ImportAllSource", "INFO", "> " & obj_count & " Relations imported" DoEvents logger "ImportAllSource", "INFO", "Import Done" End Sub ' Main entry point for ImportProject. ' Drop all forms, reports, queries, macros, modules. ' execute ImportAllSource. Public Sub ImportProject() On Error GoTo errorHandler If MsgBox("This action will delete all existing: " & vbCrLf & _ vbCrLf & _ Chr$(149) & " Tables" & vbCrLf & _ Chr$(149) & " Forms" & vbCrLf & _ Chr$(149) & " Macros" & vbCrLf & _ Chr$(149) & " Modules" & vbCrLf & _ Chr$(149) & " Queries" & vbCrLf & _ Chr$(149) & " Reports" & vbCrLf & _ vbCrLf & _ "Are you sure you want to proceed?", vbCritical + vbYesNo, _ "Import Project") <> vbYes Then Exit Sub End If Dim Db As DAO.Database Set Db = CurrentDb CloseFormsReports Debug.Print Debug.Print "Deleting Existing Objects" Debug.Print Dim rel As DAO.Relation For Each rel In CurrentDb.Relations If Not (rel.name = "MSysNavPaneGroupsMSysNavPaneGroupToObjects" Or _ rel.name = "MSysNavPaneGroupCategoriesMSysNavPaneGroups") Then CurrentDb.Relations.Delete (rel.name) End If Next Dim dbObject As Object For Each dbObject In Db.QueryDefs DoEvents If Left$(dbObject.name, 1) <> "~" Then ' Debug.Print dbObject.Name Db.QueryDefs.Delete dbObject.name End If Next Dim td As DAO.TableDef For Each td In CurrentDb.TableDefs If Left$(td.name, 4) <> "MSys" And _ Left$(td.name, 1) <> "~" Then CurrentDb.TableDefs.Delete (td.name) End If Next Dim objType As Variant Dim objTypeArray() As String Dim doc As Object ' ' Object Type Constants Const OTNAME As Byte = 0 Const OTID As Byte = 1 For Each objType In Split( _ "Forms|" & acForm & "," & _ "Reports|" & acReport & "," & _ "Scripts|" & acMacro & "," & _ "Modules|" & acModule _ , "," _ ) objTypeArray = Split(objType, "|") DoEvents For Each doc In Db.Containers(objTypeArray(OTNAME)).Documents DoEvents If (Left$(doc.name, 1) <> "~") And _ (IsNotVCS(doc.name)) Then ' Debug.Print doc.Name DoCmd.DeleteObject objTypeArray(OTID), doc.name End If Next Next Debug.Print "=================" Debug.Print "Importing Project" ImportAllSource Exit Sub errorHandler: Debug.Print "VCS_ImportExport.ImportProject: Error #" & err.number & vbCrLf & _ err.Description End Sub ' Expose for use as function, can be called by query Public Sub make() ImportProject End Sub '=================================================================================================================================== '-----------------------------------------------------------' ' Helper Functions - these should be put in their own files ' '-----------------------------------------------------------' ' Close all open forms. Private Sub CloseFormsReports() On Error GoTo errorHandler logger "CloseFormsReports", "DEBUG", "Close any opened form or report" Do While Forms.count > 0 DoCmd.Close acForm, Forms(0).name DoEvents Loop Do While Reports.count > 0 DoCmd.Close acReport, Reports(0).name DoEvents Loop Exit Sub errorHandler: logger "CloseFormsReports", "CRITICAL", "Error #" & err.number & err.Description End Sub 'errno 457 - duplicate key (& item) Public Function StrSetToCol(ByVal strSet As String, ByVal delimiter As String) As Collection 'throws errors Dim strSetArray() As String Dim col As Collection Set col = New Collection strSetArray = Split(strSet, delimiter) Dim item As Variant For Each item In strSetArray col.Add item, item Next Set StrSetToCol = col End Function ' Check if an item or key is in a collection Public Function InCollection(col As Collection, Optional vItem, Optional vKey) As Boolean On Error Resume Next Dim vColItem As Variant InCollection = False If Not IsMissing(vKey) Then col.item vKey '5 if not in collection, it is 91 if no collection exists If err.number <> 5 And err.number <> 91 Then InCollection = True End If ElseIf Not IsMissing(vItem) Then For Each vColItem In col If vColItem = vItem Then InCollection = True GoTo Exit_Proc End If Next vColItem End If Exit_Proc: Exit Function Err_Handle: Resume Exit_Proc End Function