¿Cómo se utiliza el control de versiones con el desarrollo de Access?

Resuelto Nathan DeWitt asked hace 16 años • 22 respuestas

Estoy involucrado en la actualización de una solución de Access. Tiene una buena cantidad de VBA, varias consultas, una pequeña cantidad de tablas y algunos formularios para la entrada de datos y la generación de informes. Es un candidato ideal para Access.

Quiero realizar cambios en el diseño de la tabla, VBA, las consultas y los formularios. ¿Cómo puedo realizar un seguimiento de mis cambios con el control de versiones? (Usamos Subversion, pero esto se aplica a cualquier versión). Puedo colocar todo el mdb en Subversion, pero eso almacenará un archivo binario y no podré decir que acabo de cambiar una línea de código VBA.

Pensé en copiar el código VBA en archivos separados y guardarlos, pero pude ver que rápidamente no estaban sincronizados con lo que hay en la base de datos.

Nathan DeWitt avatar Oct 09 '08 21:10 Nathan DeWitt
Aceptado

Escribimos nuestro propio script en VBScript, que utiliza el Application.SaveAsText() no documentado en Access para exportar todo el código, formulario, macro y módulos de informes. Aquí está, debería darle algunos consejos. (Cuidado: algunos de los mensajes están en alemán, pero puedes cambiarlos fácilmente).

EDITAR: Para resumir varios comentarios a continuación: Nuestro proyecto asume un archivo .adp. Para que esto funcione con .mdb/.accdb, debe cambiar OpenAccessProject() a OpenCurrentDatabase(). (Actualizado para usar OpenAccessProject()si ve una extensión .adp; de lo contrario, use OpenCurrentDatabase()).

descomponer.vbs:

' Usage:
'  CScript decompose.vbs <input file> <path>

' Converts all modules, classes, forms and macros from an Access Project file (.adp) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
'

Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Bitte den Dateinamen angeben!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sExportpath
If (WScript.Arguments.Count = 1) then
    sExportpath = ""
else
    sExportpath = WScript.Arguments(1)
End If


exportModulesTxt sADPFilename, sExportpath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function exportModulesTxt(sADPFilename, sExportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    If (sExportpath = "") then
        sExportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sExportpath & myName & "_stub." & myType

    WScript.Echo "copy stub to " & sStubADPFilename & "..."
    On Error Resume Next
        fso.CreateFolder(sExportpath)
    On Error Goto 0
    fso.CopyFile sADPFilename, sStubADPFilename

    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sStubADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sStubADPFilename
    Else
        oApplication.OpenCurrentDatabase sStubADPFilename
    End If

    oApplication.Visible = false

    dim dctDelete
    Set dctDelete = CreateObject("Scripting.Dictionary")
    WScript.Echo "exporting..."
    Dim myObj
    For Each myObj In oApplication.CurrentProject.AllForms
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acForm, myObj.fullname, sExportpath & "\" & myObj.fullname & ".form"
        oApplication.DoCmd.Close acForm, myObj.fullname
        dctDelete.Add "FO" & myObj.fullname, acForm
    Next
    For Each myObj In oApplication.CurrentProject.AllModules
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acModule, myObj.fullname, sExportpath & "\" & myObj.fullname & ".bas"
        dctDelete.Add "MO" & myObj.fullname, acModule
    Next
    For Each myObj In oApplication.CurrentProject.AllMacros
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acMacro, myObj.fullname, sExportpath & "\" & myObj.fullname & ".mac"
        dctDelete.Add "MA" & myObj.fullname, acMacro
    Next
    For Each myObj In oApplication.CurrentProject.AllReports
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acReport, myObj.fullname, sExportpath & "\" & myObj.fullname & ".report"
        dctDelete.Add "RE" & myObj.fullname, acReport
    Next

    WScript.Echo "deleting..."
    dim sObjectname
    For Each sObjectname In dctDelete
        WScript.Echo "  " & Mid(sObjectname, 3)
        oApplication.DoCmd.DeleteObject dctDelete(sObjectname), Mid(sObjectname, 3)
    Next

    oApplication.CloseCurrentDatabase
    oApplication.CompactRepair sStubADPFilename, sStubADPFilename & "_"
    oApplication.Quit

    fso.CopyFile sStubADPFilename & "_", sStubADPFilename
    fso.DeleteFile sStubADPFilename & "_"


End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

Si necesita un comando en el que se puede hacer clic, en lugar de usar la línea de comando, cree un archivo llamado "decompose.cmd" con

cscript decompose.vbs youraccessapplication.adp

De forma predeterminada, todos los archivos exportados van a la subcarpeta "Scripts" de su aplicación Access. El archivo .adp/mdb también se copia en esta ubicación (con un sufijo "stub") y se eliminan todos los módulos exportados, lo que lo hace realmente pequeño.

DEBE registrar este código auxiliar con los archivos fuente, porque la mayoría de las configuraciones de acceso y las barras de menú personalizadas no se pueden exportar de ninguna otra manera. Solo asegúrese de confirmar los cambios solo en este archivo, si realmente cambió alguna configuración o menú.

Nota: Si tiene algún Autoexec-Makros definido en su aplicación, es posible que deba mantener presionada la tecla Shift cuando invoque la descomposición para evitar que se ejecute e interfiera con la exportación.

Por supuesto, también existe el script inverso, para construir la aplicación desde el directorio "Fuente":

componer.vbs:

' Usage:
'  WScript compose.vbs <file> <path>

' Converts all modules, classes, forms and macros in a directory created by "decompose.vbs"
' and composes then into an Access Project file (.adp). This overwrites any existing Modules with the
' same names without warning!!!
' Requires Microsoft Access.

Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3

Const acCmdCompileAndSaveAllModules = &H7E

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Please enter the file name!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sPath
If (WScript.Arguments.Count = 1) then
    sPath = ""
else
    sPath = WScript.Arguments(1)
End If


importModulesTxt sADPFilename, sPath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function importModulesTxt(sADPFilename, sImportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    ' Build file and pathnames
    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    ' if no path was given as argument, use a relative directory
    If (sImportpath = "") then
        sImportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sImportpath & myName & "_stub." & myType

    ' check for existing file and ask to overwrite with the stub
    if (fso.FileExists(sADPFilename)) Then
        WScript.StdOut.Write sADPFilename & " exists. Overwrite? (y/n) "
        dim sInput
        sInput = WScript.StdIn.Read(1)
        if (sInput <> "y") Then
            WScript.Quit
        end if

        fso.CopyFile sADPFilename, sADPFilename & ".bak"
    end if

    fso.CopyFile sStubADPFilename, sADPFilename

    ' launch MSAccess
    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sADPFilename
    Else
        oApplication.OpenCurrentDatabase sADPFilename
    End If
    oApplication.Visible = false

    Dim folder
    Set folder = fso.GetFolder(sImportpath)

    ' load each file from the import path into the stub
    Dim myFile, objectname, objecttype
    for each myFile in folder.Files
        objecttype = fso.GetExtensionName(myFile.Name)
        objectname = fso.GetBaseName(myFile.Name)
        WScript.Echo "  " & objectname & " (" & objecttype & ")"

        if (objecttype = "form") then
            oApplication.LoadFromText acForm, objectname, myFile.Path
        elseif (objecttype = "bas") then
            oApplication.LoadFromText acModule, objectname, myFile.Path
        elseif (objecttype = "mac") then
            oApplication.LoadFromText acMacro, objectname, myFile.Path
        elseif (objecttype = "report") then
            oApplication.LoadFromText acReport, objectname, myFile.Path
        end if

    next

    oApplication.RunCommand acCmdCompileAndSaveAllModules
    oApplication.Quit
End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

Nuevamente, esto va con un complemento "compose.cmd" que contiene:

cscript compose.vbs youraccessapplication.adp

Le pide que confirme la sobrescritura de su aplicación actual y primero crea una copia de seguridad, si lo hace. Luego recopila todos los archivos fuente en el directorio fuente y los vuelve a insertar en el código auxiliar.

¡Divertirse!

Oliver avatar Oct 17 '2008 06:10 Oliver

La solución de composición/descomposición publicada por Oliver es excelente, pero tiene algunos problemas:

  • Los archivos están codificados como UCS-2 (UTF-16), lo que puede hacer que los sistemas/herramientas de control de versiones consideren que los archivos son binarios.
  • Los archivos contienen mucha información que cambia con frecuencia: sumas de verificación, información de la impresora y más. Este es un problema grave si desea diferencias limpias o necesita cooperar en el proyecto.

Estaba planeando solucionar este problema yo mismo, pero descubrí que ya hay una buena solución disponible: timabell/msaccess-vcs-integration en GitHub. Probé msaccess-vcs-integration y funciona muy bien.

Actualizado el 3 de marzo de 2015 : el proyecto fue originalmente mantenido/propiedad de bkidwell en Github, pero se transfirió a timabell ; el enlace de arriba al proyecto se actualiza en consecuencia. Hay algunas bifurcaciones del proyecto original de bkidwell, por ejemplo de ArminBra y de matonb , que AFAICT no deberían usarse.

La desventaja de usar msaccess-vcs-integration en comparación con la solución de descomposición de Olivers:

  • Es significativamente más lento. Estoy seguro de que el problema de la velocidad se puede solucionar, pero no necesito exportar mi proyecto a texto con tanta frecuencia...
  • No crea un proyecto auxiliar de Access con el material exportado eliminado. Esto también se puede solucionar (adoptando código del script de descomposición), pero nuevamente, no es tan importante.

De todos modos, mi recomendación clara es msaccess-vcs-integration. Resolvió todos los problemas que tuve al usar Git en los archivos exportados.

hansfn avatar Nov 08 '2014 18:11 hansfn