VirtualBox

vbox的更動 56308 路徑 trunk/src/bldprogs


忽略:
時間撮記:
2015-6-9 下午10:30:42 (9 年 以前)
作者:
vboxsync
訊息:

scmsubversion.cpp,Makefile.kmk: Dynamic svn+apr API resolving, implemented property querying and file/dir-in-WC checks which speeds things up a lot.

位置:
trunk/src/bldprogs
檔案:
修改 2 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/bldprogs/Makefile.kmk

    r56301 r56308  
    4242        scmstream.cpp \
    4343        scmsubversion.cpp
     44 ifdef VBOX_PATH_SUBVERSION_INCS
     45  scm_INCS += $(VBOX_PATH_SUBVERSION_INCS) $(VBOX_PATH_APACHE_RUNTIME_INCS)
     46  scm_DEFS += SCM_WITH_SVN_HEADERS
     47 endif
    4448
    4549 BLDPROGS += VBoxCPP
  • trunk/src/bldprogs/scmsubversion.cpp

    r48959 r56308  
    55
    66/*
    7  * Copyright (C) 2010-2012 Oracle Corporation
     7 * Copyright (C) 2010-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1616 */
    1717
    18 #define SCM_WITHOUT_LIBSVN
     18#define SCM_WITH_DYNAMIC_LIB_SVN
    1919
    2020/*******************************************************************************
     
    2525#include <iprt/dir.h>
    2626#include <iprt/env.h>
     27#include <iprt/err.h>
    2728#include <iprt/file.h>
    28 #include <iprt/err.h>
    2929#include <iprt/getopt.h>
     30#include <iprt/handle.h>
    3031#include <iprt/initterm.h>
     32#include <iprt/ldr.h>
    3133#include <iprt/mem.h>
    3234#include <iprt/message.h>
    3335#include <iprt/param.h>
    3436#include <iprt/path.h>
     37#include <iprt/pipe.h>
     38#include <iprt/poll.h>
    3539#include <iprt/process.h>
    3640#include <iprt/stream.h>
     
    3842
    3943#include "scm.h"
     44
     45#if defined(SCM_WITH_DYNAMIC_LIB_SVN) && defined(SCM_WITH_SVN_HEADERS)
     46# include <svn_client.h>
     47#endif
     48
     49
     50/*******************************************************************************
     51*   Defined Constants And Macros                                               *
     52*******************************************************************************/
     53#ifdef SCM_WITH_DYNAMIC_LIB_SVN
     54# if defined(RT_OS_WINDOWS) && defined(RT_ARCH_X86)
     55#  define APR_CALL                       __stdcall
     56#  define SVN_CALL                       /* __stdcall ?? */
     57# else
     58#  define APR_CALL
     59#  define SVN_CALL
     60# endif
     61#endif
     62#if defined(SCM_WITH_DYNAMIC_LIB_SVN) && !defined(SCM_WITH_SVN_HEADERS)
     63# define SVN_ERR_MISC_CATEGORY_START    200000
     64# define SVN_ERR_UNVERSIONED_RESOURCE   (SVN_ERR_MISC_CATEGORY_START + 5)
     65#endif
     66
     67
     68/*******************************************************************************
     69*   Structures and Typedefs                                                    *
     70*******************************************************************************/
     71#if defined(SCM_WITH_DYNAMIC_LIB_SVN) && !defined(SCM_WITH_SVN_HEADERS)
     72typedef int                         apr_status_t;
     73typedef int64_t                     apr_time_t;
     74typedef struct apr_pool_t           apr_pool_t;
     75typedef struct apr_hash_t           apr_hash_t;
     76typedef struct apr_hash_index_t     apr_hash_index_t;
     77typedef struct apr_array_header_t   apr_array_header_t;
     78
     79
     80typedef struct svn_error_t
     81{
     82    apr_status_t                    apr_err;
     83    const char                     *_dbgr_message;
     84    struct svn_error_t             *_dbgr_child;
     85    apr_pool_t                     *_dbgr_pool;
     86    const char                     *_dbgr_file;
     87    long                            _dbgr_line;
     88} svn_error_t;
     89typedef int                         svn_boolean_t;
     90typedef long int                    svn_revnum_t;
     91typedef struct svn_client_ctx_t     svn_client_ctx_t;
     92typedef enum svn_opt_revision_kind
     93{
     94    svn_opt_revision_unspecified = 0,
     95    svn_opt_revision_number,
     96    svn_opt_revision_date,
     97    svn_opt_revision_committed,
     98    svn_opt_revision_previous,
     99    svn_opt_revision_base,
     100    svn_opt_revision_working,
     101    svn_opt_revision_head
     102} svn_opt_revision_kind;
     103typedef union svn_opt_revision_value_t
     104{
     105    svn_revnum_t                    number;
     106    apr_time_t                      date;
     107} svn_opt_revision_value_t;
     108typedef struct svn_opt_revision_t
     109{
     110  svn_opt_revision_kind             kind;
     111  svn_opt_revision_value_t          value;
     112} svn_opt_revision_t;
     113typedef enum svn_depth_t
     114{
     115    svn_depth_unknown = -2,
     116    svn_depth_exclude,
     117    svn_depth_empty,
     118    svn_depth_files,
     119    svn_depth_immediates,
     120    svn_depth_infinity
     121} svn_depth_t;
     122
     123#endif /* SCM_WITH_DYNAMIC_LIB_SVN && !SCM_WITH_SVN_HEADERS */
    40124
    41125
     
    49133    kScmSvnVersion_1_6,
    50134    kScmSvnVersion_1_7,
     135    kScmSvnVersion_1_8,
    51136    kScmSvnVersion_End
    52137}           g_enmSvnVersion = kScmSvnVersion_Ancient;
    53138
    54139
    55 #ifdef SCM_WITHOUT_LIBSVN
     140#ifdef SCM_WITH_DYNAMIC_LIB_SVN
     141/** Set if all the function pointers are valid. */
     142static bool                             g_fSvnFunctionPointersValid;
     143/** @name SVN and APR imports.
     144 * @{ */
     145static apr_status_t          (APR_CALL *g_pfnAprInitialize)(void);
     146static apr_hash_index_t *    (APR_CALL *g_pfnAprHashFirst)(apr_pool_t *pPool, apr_hash_t *pHashTab);
     147static apr_hash_index_t *    (APR_CALL *g_pfnAprHashNext)(apr_hash_index_t *pCurIdx);
     148static void *                (APR_CALL *g_pfnAprHashThisVal)(apr_hash_index_t *pHashIdx);
     149static apr_pool_t *          (SVN_CALL *g_pfnSvnPoolCreateEx)(apr_pool_t *pParent, void *pvAllocator);
     150static void                  (APR_CALL *g_pfnAprPoolClear)(apr_pool_t *pPool);
     151static void                  (APR_CALL *g_pfnAprPoolDestroy)(apr_pool_t *pPool);
     152
     153static svn_error_t *         (SVN_CALL *g_pfnSvnClientCreateContext)(svn_client_ctx_t **ppCtx, apr_pool_t *pPool);
     154static svn_error_t *         (SVN_CALL *g_pfnSvnClientPropGet4)(apr_hash_t **ppHashProps, const char *pszPropName,
     155                                                                const char *pszTarget, const svn_opt_revision_t *pPeggedRev,
     156                                                                const svn_opt_revision_t *pRevision, svn_revnum_t *pActualRev,
     157                                                                svn_depth_t enmDepth, const apr_array_header_t *pChangeList,
     158                                                                svn_client_ctx_t *pCtx, apr_pool_t *pResultPool,
     159                                                                apr_pool_t *pScratchPool);
     160/**@} */
     161#endif
     162
     163
    56164
    57165/**
     
    78186}
    79187
    80 #include <iprt/handle.h>
    81 #include <iprt/pipe.h>
    82 #include <iprt/poll.h>
    83188
    84189/**
     
    548653
    549654
     655#ifdef SCM_WITH_DYNAMIC_LIB_SVN
     656/**
     657 * Attempts to resolve the necessary subversion and apache portable runtime APIs
     658 * we require dynamically.
     659 *
     660 * Will set all global function pointers and g_fSvnFunctionPointersValid to true
     661 * on success.
     662 */
     663static void scmSvnTryResolveFunctions(void)
     664{
     665    char szPath[RTPATH_MAX];
     666    int rc = RTStrCopy(szPath, sizeof(szPath), g_szSvnPath);
     667    if (RT_SUCCESS(rc))
     668    {
     669        RTPathStripFilename(szPath);
     670        char *pszEndPath = strchr(szPath, '\0');
     671# ifdef RT_OS_WINDOWS
     672        RTPathChangeToDosSlashes(szPath, false);
     673# endif
     674
     675        /*
     676         * Try various prefixes/suffxies/locations.
     677         */
     678        static struct
     679        {
     680            const char *pszPrefix;
     681            const char *pszSuffix;
     682        } const s_aVariations[] =
     683        {
     684# ifdef RT_OS_WINDOWS
     685            { "SlikSvn-lib", "-1.dll" },    /* SlikSVN */
     686            { "lib", "-1.dll" },            /* Win32Svn,CollabNet,++ */
     687# elif defined(RT_OS_DARWIN)
     688            { "../lib/lib", "-1.dylib" },
     689# else
     690            { "../lib/lib", ".so" },
     691            { "../lib/lib", "-1.so" },
     692# endif
     693        };
     694        for (unsigned iVar = 0; RT_ELEMENTS(s_aVariations); iVar++)
     695        {
     696            /*
     697             * Try load the svn_client library ...
     698             */
     699            struct
     700            {
     701                const char *pszBaseName;
     702                RTLDRMOD    hMod;
     703            } aLibraries[] =
     704            {
     705                { "svn_client", NIL_RTLDRMOD },
     706                { "svn_subr",   NIL_RTLDRMOD },
     707                { "apr",        NIL_RTLDRMOD },
     708            };
     709            rc = VINF_SUCCESS;
     710            unsigned iLib;
     711            for (iLib = 0; iLib < RT_ELEMENTS(aLibraries) && RT_SUCCESS(rc); iLib++)
     712            {
     713                *pszEndPath = '\0';
     714                rc = RTPathAppend(szPath, sizeof(szPath), s_aVariations[iVar].pszPrefix);
     715                if (RT_SUCCESS(rc))
     716                    rc = RTStrCat(szPath, sizeof(szPath), aLibraries[iLib].pszBaseName);
     717                if (RT_SUCCESS(rc))
     718                    rc = RTStrCat(szPath, sizeof(szPath), s_aVariations[iVar].pszSuffix);
     719                if (RT_SUCCESS(rc))
     720                {
     721# ifdef RT_OS_WINDOWS
     722                    RTPathChangeToDosSlashes(pszEndPath, false);
     723# endif
     724                    rc = RTLdrLoadEx(szPath, &aLibraries[iLib].hMod, RTLDRLOAD_FLAGS_NT_SEARCH_DLL_LOAD_DIR , NULL);
     725                }
     726            }
     727            if (iLib == RT_ELEMENTS(aLibraries) && RT_SUCCESS(rc))
     728            {
     729                static const struct
     730                {
     731                    unsigned    iLib;
     732                    const char *pszSymbol;
     733                    PFNRT      *ppfn;
     734                } s_aSymbols[] =
     735                {
     736                    { 2, "apr_initialize",              (PFNRT *)&g_pfnAprInitialize },
     737                    { 2, "apr_hash_first",              (PFNRT *)&g_pfnAprHashFirst },
     738                    { 2, "apr_hash_next",               (PFNRT *)&g_pfnAprHashNext },
     739                    { 2, "apr_hash_this_val",           (PFNRT *)&g_pfnAprHashThisVal },
     740                    { 1, "svn_pool_create_ex",          (PFNRT *)&g_pfnSvnPoolCreateEx },
     741                    { 2, "apr_pool_clear",              (PFNRT *)&g_pfnAprPoolClear },
     742                    { 2, "apr_pool_destroy",            (PFNRT *)&g_pfnAprPoolDestroy },
     743                    { 0, "svn_client_create_context",   (PFNRT *)&g_pfnSvnClientCreateContext },
     744                    { 0, "svn_client_propget4",         (PFNRT *)&g_pfnSvnClientPropGet4 },
     745                };
     746                for (unsigned i = 0; i < RT_ELEMENTS(s_aSymbols); i++)
     747                {
     748                    rc = RTLdrGetSymbol(aLibraries[s_aSymbols[i].iLib].hMod, s_aSymbols[i].pszSymbol,
     749                                        (void **)(uintptr_t)s_aSymbols[i].ppfn);
     750                    if (RT_FAILURE(rc))
     751                    {
     752                        ScmVerbose(NULL, 0, "Failed to resolve '%s' in '%s'",
     753                                   s_aSymbols[i].pszSymbol, aLibraries[s_aSymbols[i].iLib].pszBaseName);
     754                        break;
     755                    }
     756                }
     757                if (RT_SUCCESS(rc))
     758                {
     759                    apr_status_t rc = g_pfnAprInitialize();
     760                    if (rc == 0)
     761                    {
     762                        ScmVerbose(NULL, 1, "Found subversion APIs.\n");
     763                        g_fSvnFunctionPointersValid = true;
     764                    }
     765                    else
     766                    {
     767                        ScmVerbose(NULL, 0, "apr_initialize failed: %#x (%d)\n", rc, rc);
     768                        AssertMsgFailed(("%#x (%d)\n", rc, rc));
     769                    }
     770                    return;
     771                }
     772            }
     773
     774            while (iLib-- > 0)
     775                RTLdrClose(aLibraries[iLib].hMod);
     776        }
     777    }
     778}
     779#endif /* SCM_WITH_DYNAMIC_LIB_SVN */
     780
     781
    550782/**
    551783 * Finds the svn binary, updating g_szSvnPath and g_enmSvnVersion.
     
    588820    {
    589821        char *pszStripped = RTStrStrip(pszVersion);
    590         if (RTStrVersionCompare(pszVersion, "1.7") >= 0)
     822        if (RTStrVersionCompare(pszVersion, "1.8") >= 0)
     823            g_enmSvnVersion = kScmSvnVersion_1_8;
     824        else if (RTStrVersionCompare(pszVersion, "1.7") >= 0)
    591825            g_enmSvnVersion = kScmSvnVersion_1_7;
    592826        else if (RTStrVersionCompare(pszVersion, "1.6") >= 0)
     
    598832    else
    599833        g_enmSvnVersion = kScmSvnVersion_Ancient;
     834
     835#ifdef SCM_WITH_DYNAMIC_LIB_SVN
     836    /*
     837     * If we got version 1.8 or later, try see if we can locate a few of the
     838     * simpler SVN APIs.
     839     */
     840    g_fSvnFunctionPointersValid = false;
     841    if (g_enmSvnVersion >= kScmSvnVersion_1_8)
     842        scmSvnTryResolveFunctions();
     843#endif
    600844}
    601845
     
    658902}
    659903
    660 #endif /* SCM_WITHOUT_LIBSVN */
     904
     905#ifdef SCM_WITH_DYNAMIC_LIB_SVN
     906
     907/**
     908 * Wrapper around RTPathAbs.
     909 * @returns Same as RTPathAbs.
     910 * @param   pszPath             The relative path.
     911 * @param   pszAbsPath          Where to return the absolute path.
     912 * @param   cbAbsPath           Size of the @a pszAbsPath buffer.
     913 */
     914static int scmSvnAbsPath(const char *pszPath, char *pszAbsPath, size_t cbAbsPath)
     915{
     916    int rc = RTPathAbs(pszPath, pszAbsPath, cbAbsPath);
     917# if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     918    if (RT_SUCCESS(rc))
     919        RTPathChangeToUnixSlashes(pszAbsPath, true /*fForce*/);
     920# endif
     921    return rc;
     922}
     923
     924
     925/**
     926 * Checks if @a pszPath exists in the current WC.
     927 *
     928 * @returns true, false or -1. In the latter case, please use the fallback.
     929 * @param   pszPath         Path to the object that should be investigated.
     930 */
     931static int scmSvnIsObjectInWorkingCopy(const char *pszPath)
     932{
     933    int rc = -1;
     934
     935    /* svn_client_propget4 and later requires absolute target path. */
     936    char szAbsPath[RTPATH_MAX];
     937    int  rc2 = scmSvnAbsPath(pszPath, szAbsPath, sizeof(szAbsPath));
     938    if (RT_SUCCESS(rc2))
     939    {
     940        /* Create calling context. */
     941        apr_pool_t *pPool = g_pfnSvnPoolCreateEx(NULL, NULL);
     942        if (pPool)
     943        {
     944            svn_client_ctx_t *pCtx = NULL;
     945            svn_error_t *pErr = g_pfnSvnClientCreateContext(&pCtx, pPool);
     946            if (!pErr)
     947            {
     948                /* Make the call. */
     949                apr_hash_t         *pHash = NULL;
     950                svn_opt_revision_t  Rev;
     951                RT_ZERO(Rev);
     952                Rev.kind          = svn_opt_revision_base;
     953                Rev.value.number  = -1L;
     954                pErr = g_pfnSvnClientPropGet4(&pHash, "svn:no-such-property", szAbsPath, &Rev, &Rev,
     955                                              NULL /*pActualRev*/, svn_depth_empty, NULL /*pChangeList*/, pCtx, pPool, pPool);
     956                if (!pErr)
     957                    rc = true;
     958                else if (pErr->apr_err == SVN_ERR_UNVERSIONED_RESOURCE)
     959                    rc = false;
     960            }
     961            g_pfnAprPoolDestroy(pPool);
     962        }
     963    }
     964    return rc;
     965}
     966
     967#endif /* SCM_WITH_DYNAMIC_LIB_SVN */
     968
    661969
    662970/**
     
    668976bool ScmSvnIsInWorkingCopy(PSCMRWSTATE pState)
    669977{
    670 #ifdef SCM_WITHOUT_LIBSVN
    671978    scmSvnFindSvnBinary(pState);
     979
     980#ifdef SCM_WITH_DYNAMIC_LIB_SVN
     981    if (g_fSvnFunctionPointersValid)
     982    {
     983        int rc = scmSvnIsObjectInWorkingCopy(pState->pszFilename);
     984        if (rc == (int)true || rc == (int)false)
     985            return rc == (int)true;
     986    }
     987
     988    /* Fallback: */
     989#endif
    672990    if (g_enmSvnVersion < kScmSvnVersion_1_7)
    673991    {
     
    6911009        }
    6921010    }
    693 
    694 #else
    695     NOREF(pState);
    696 #endif
    6971011    return false;
    6981012}
     1013
    6991014
    7001015/**
     
    7061021bool ScmSvnIsDirInWorkingCopy(const char *pszDir)
    7071022{
    708 #ifdef SCM_WITHOUT_LIBSVN
    7091023    scmSvnFindSvnBinary(NULL);
     1024
     1025#ifdef SCM_WITH_DYNAMIC_LIB_SVN
     1026    if (g_fSvnFunctionPointersValid)
     1027    {
     1028        int rc = scmSvnIsObjectInWorkingCopy(pszDir);
     1029        if (rc == (int)true || rc == (int)false)
     1030            return rc == (int)true;
     1031    }
     1032
     1033    /* Fallback: */
     1034#endif
    7101035    if (g_enmSvnVersion < kScmSvnVersion_1_7)
    7111036    {
     
    7291054        }
    7301055    }
    731 
    732 #else
    733     NOREF(pState);
    734 #endif
    7351056    return false;
    7361057}
     1058
     1059
     1060#ifdef SCM_WITH_DYNAMIC_LIB_SVN
     1061/**
     1062 * Checks if @a pszPath exists in the current WC.
     1063 *
     1064 * @returns IPRT status code - VERR_NOT_SUPPORT if fallback should be attempted.
     1065 * @param   pszPath         Path to the object that should be investigated.
     1066 * @param   pszProperty     The property name.
     1067 * @param   ppszValue       Where to return the property value. Optional.
     1068 */
     1069static int scmSvnQueryPropertyUsingApi(const char *pszPath, const char *pszProperty, char **ppszValue)
     1070{
     1071    int rc = VERR_NOT_SUPPORTED;
     1072
     1073    /* svn_client_propget4 and later requires absolute target path. */
     1074    char szAbsPath[RTPATH_MAX];
     1075    int  rc2 = scmSvnAbsPath(pszPath, szAbsPath, sizeof(szAbsPath));
     1076    if (RT_SUCCESS(rc2))
     1077    {
     1078        /* Create calling context. */
     1079        apr_pool_t *pPool = g_pfnSvnPoolCreateEx(NULL, NULL);
     1080        if (pPool)
     1081        {
     1082            svn_client_ctx_t *pCtx = NULL;
     1083            svn_error_t *pErr = g_pfnSvnClientCreateContext(&pCtx, pPool);
     1084            if (!pErr)
     1085            {
     1086                /* Make the call. */
     1087                apr_hash_t         *pHash = NULL;
     1088                svn_opt_revision_t  Rev;
     1089                RT_ZERO(Rev);
     1090                Rev.kind          = svn_opt_revision_base;
     1091                Rev.value.number  = -1L;
     1092                pErr = g_pfnSvnClientPropGet4(&pHash, pszProperty, szAbsPath, &Rev, &Rev,
     1093                                              NULL /*pActualRev*/, svn_depth_empty, NULL /*pChangeList*/, pCtx, pPool, pPool);
     1094                if (!pErr)
     1095                {
     1096                    /* Get the first value, if any. */
     1097                    rc = VERR_NOT_FOUND;
     1098                    apr_hash_index_t *pHashIdx = g_pfnAprHashFirst(pPool, pHash);
     1099                    if (pHashIdx)
     1100                    {
     1101                        const char **ppszFirst = (const char **)g_pfnAprHashThisVal(pHashIdx);
     1102                        if (ppszFirst && *ppszFirst)
     1103                            rc = RTStrDupEx(ppszValue, *ppszFirst);
     1104                    }
     1105                }
     1106                else if (pErr->apr_err == SVN_ERR_UNVERSIONED_RESOURCE)
     1107                    rc = VERR_INVALID_STATE;
     1108                else
     1109                    rc = VERR_GENERAL_FAILURE;
     1110            }
     1111            g_pfnAprPoolDestroy(pPool);
     1112        }
     1113    }
     1114    return rc;
     1115}
     1116#endif /* SCM_WITH_DYNAMIC_LIB_SVN */
     1117
    7371118
    7381119/**
     
    7511132int ScmSvnQueryProperty(PSCMRWSTATE pState, const char *pszName, char **ppszValue)
    7521133{
     1134    int rc;
     1135
    7531136    /*
    7541137     * Look it up in the scheduled changes.
     
    7661149        }
    7671150
    768 #ifdef SCM_WITHOUT_LIBSVN
    769     int rc;
    7701151    scmSvnFindSvnBinary(pState);
     1152
     1153#ifdef SCM_WITH_DYNAMIC_LIB_SVN
     1154    if (g_fSvnFunctionPointersValid)
     1155    {
     1156        rc = scmSvnQueryPropertyUsingApi(pState->pszFilename, pszName, ppszValue);
     1157        if (rc != VERR_NOT_SUPPORTED)
     1158            return rc;
     1159        /* Fallback: */
     1160    }
     1161#endif
     1162
    7711163    if (g_enmSvnVersion < kScmSvnVersion_1_7)
    7721164    {
     
    9151307    }
    9161308    return rc;
    917 
    918 #else
    919     NOREF(pState);
    920 #endif
    921     return VERR_NOT_FOUND;
    9221309}
    9231310
     
    10311418int ScmSvnApplyChanges(PSCMRWSTATE pState)
    10321419{
    1033 #ifdef SCM_WITHOUT_LIBSVN
    10341420    scmSvnFindSvnBinary(pState);
     1421
     1422#ifdef SCM_WITH_LATER
     1423    if (0)
     1424    {
     1425        return ...;
     1426    }
     1427
     1428    /* Fallback: */
     1429#endif
    10351430
    10361431    /*
     
    10551450
    10561451    return VINF_SUCCESS;
    1057 #else
    1058     return VERR_NOT_IMPLEMENTED;
    1059 #endif
    1060 }
    1061 
     1452}
     1453
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette