git submodule 使用本地镜像

通常,主项目会由开发人员自己主动跟踪并更新至社区的最新的代码,但对于主项目中引用的第三方模块(submodule)一般都不会太关注,主项目也不会频繁更新对它的引用,但在构建时(特别是 CI 构建时)可能需要频繁的从 github 等第三方频繁的拉取代码,在 GFW 和内部网络双重控制的网络环境下,实际上大大延长了构建所需的时间,对于这些第三方模块,可以使用本地的 git 镜像仓库进行加速构建。

需要注意的是第三方模块自身又可能引用第三方模块,且引用的第三方模块可能又与主项目引用的同名但属于不同的 git 仓库,因此使用本地镜像的关键是对第三方模块 URL 的替换操作。

参考脚本如下:

#!/bin/bash -x

mirrors() {
    cat > .git_submodule_mirrors <<EOF
ceph-object-corpus http://src.example.com/ceph/ceph-object-corpus.git
src/civetweb http://src.example.com/ceph/civetweb.git
src/libs3 http://src.example.com/ceph/libs3.git
src/mongoose http://src.example.com/ceph/mongoose.git
src/leveldb http://src.example.com/ceph/leveldb.git
src/erasure-code/jerasure/jerasure http://src.example.com/ceph/jerasure.git
src/erasure-code/jerasure/gf-complete http://src.example.com/ceph/gf-complete.git
src/rocksdb http://src.example.com/ceph/rocksdb.git
ceph-erasure-code-corpus http://src.example.com/ceph/ceph-erasure-code-corpus.git
src/gmock http://src.example.com/ceph/gmock.git
src/dpdk http://src.example.com/ceph/dpdk.git
src/spdk http://src.example.com/ceph/spdk.git
dpdk spdk http://src.example.com/spdk/dpdk.git
src/xxHash http://src.example.com/ceph/xxHash.git
gtest http://src.example.com/ceph/gtest.git
src/isa-l http://src.example.com/ceph/isa-l.git
src/googletest http://src.example.com/ceph/googletest.git
src/lua http://src.example.com/ceph/lua.git
src/boost http://src.example.com/boostorg/boost.git
src/Beast http://src.example.com/ceph/Beast.git
src/zetascale http://src.example.com/ceph/zetascale.git
src/zstd http://src.example.com/facebook/zstd.git
src/crypto/isa-l/isa-l_crypto http://src.example.com/01org/isa-l_crypto.git
src/blkin http://src.example.com/ceph/blkin.git
src/rapidjson http://src.example.com/ceph/rapidjson.git
thirdparty/gtest http://src.example.com/google/googletest.git
src/dmclock http://src.example.com/ceph/dmclock.git
src/seastar http://src.example.com/ceph/seastar.git
dpdk seastar http://src.example.com/ceph/dpdk.git
src/fmt http://src.example.com/ceph/fmt.git
fmt seastar http://src.example.com/ceph/fmt.git
src/c-ares http://src.example.com/ceph/c-ares.git
extern/dpdk http://src.example.com/scylladb/dpdk.git
intel-ipsec-mb http://src.example.com/spdk/intel-ipsec-mb.git
src/pybind11 http://src.example.com/pybind/pybind11.git
tools/clang http://src.example.com/wjakob/clang-cindex-python3.git
src/json http://src.example.com/nlohmann/json.git
src/pybind/mgr/rook/rook-client-python http://src.example.com/ceph/rook-client-python.git
s3select http://src.example.com/ceph/s3select.git
src/spawn http://src.example.com/ceph/spawn.git
isa-l spdk http://src.example.com/spdk/isa-l.git
ocf spdk http://src.example.com/Open-CAS/ocf.git
test/dependency/googletest spawn http://src.example.com/google/googletest.git
EOF
}

replace() {
    mirrors

    git submodule init

    for submodule in $(git config -l | grep submodule | cut -d'.' -f2 | uniq); do
        grep -i -e "^${submodule}[[:space:]]" .git_submodule_mirrors | while read -r line; do
            fields=$(echo ${line} | wc -w)
            if [ ${fields} -eq 2 ]; then
                giturl=$(echo ${line} | cut -d" " -f2)
                git config --replace-all submodule.${submodule}.url ${giturl}
            else
                curmodule=$(basename $(pwd))
                parent=$(echo ${line} | cut -d" " -f2)
                if [ ${curmodule} = ${parent} ]; then
                    giturl=$(echo ${line} | cut -d" " -f3)
                    git config --replace-all submodule.${submodule}.url ${giturl}
                fi
            fi
        done
    done

    git submodule update --init

    rm -f .git_submodule_mirrors
}

. /etc/os-release

if [ x${ID} = xcentos ]; then
    export -f mirrors
    export -f replace

    replace
    git submodule foreach bash -x -c 'replace'

    unset -f mirrors
    unset -f replace
elif [ x${ID} = xubuntu -o x${ID} = xalpine ]; then
    replace
    git submodule foreach bash -x -c "$(declare -pf mirrors replace); replace"
else
    echo 'not supported platform, exiting'
    exit 1
fi

当然,上面的脚本一般会和如下的清理脚本一起使用,即先清理掉所有的第三方模块,然后再重新同步(假设上面的脚本为 use-mirror.sh):

#!/bin/bash -x

CUR_DIR=$(cd -P $(dirname $0) && pwd -P)

git submodule deinit -f .
#git submodule foreach 'git clean -fdx && git reset --hard'
rm -rf ceph-object-corpus
rm -rf src/civetweb
rm -rf src/libs3
rm -rf src/mongoose
rm -rf src/leveldb
rm -rf src/erasure-code/jerasure/jerasure
rm -rf src/erasure-code/jerasure/gf-complete
rm -rf src/rocksdb
rm -rf ceph-erasure-code-corpus
rm -rf src/gmock
rm -rf src/dpdk
rm -rf src/spdk
rm -rf src/xxHash
rm -rf gtest
rm -rf src/isa-l
rm -rf src/googletest
rm -rf src/lua
rm -rf src/boost
rm -rf src/Beast
rm -rf src/zetascale
rm -rf src/zstd
rm -rf src/crypto/isa-l/isa-l_crypto
rm -rf src/blkin
rm -rf src/rapidjson
rm -rf thirdparty/gtest
rm -rf src/dmclock
rm -rf src/seastar
rm -rf src/fmt
rm -rf src/c-ares
rm -rf src/pybind11
rm -rf src/json
rm -rf src/pybind/mgr/rook/rook-client-python
rm -rf src/s3select
rm -rf src/spawn
rm -rf .git/modules/
git clean -fdx && git reset --hard
git submodule sync
$CUR_DIR/use-mirror.sh
git submodule update --init
git clean -fdx

最后修改于 2019-04-22