go module笔记与源码分析

简介

  • 零零散散的关于go module的笔记, 通过源码来理解这些点

go mod源码位置

关于版本选择

  • 同一个大版本取最大版本号

    • main依赖了(A1.1.0, B1.2.0), B1.2.0依赖了(A1.0.0), 则最终构建阶段大家都用A1.1.0编译
  • 版本从信息从/@v/list获取, 如果为空则取走@latest获取最新版本号, 在拿最新版本号取拉包

  • 官方版本规则

  • 核心逻辑

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    func (p *proxyRepo) Versions(prefix string) ([]string, error) {
    data, err := p.getBytes("@v/list") // 获取list文件内容
    if err != nil {
    return nil, p.versionError("", err)
    }
    var list []string
    for _, line := range strings.Split(string(data), "\n") {
    f := strings.Fields(line)
    if len(f) >= 1 && semver.IsValid(f[0]) && strings.HasPrefix(f[0], prefix) && !IsPseudoVersion(f[0]) {
    list = append(list, f[0])
    }
    }
    SortVersions(list) // 对list里面的版本进行排序
    return list, nil
    }

    // IsPseudoVersion reports whether v is a pseudo-version.
    func IsPseudoVersion(v string) bool {
    return strings.Count(v, "-") >= 2 && semver.IsValid(v) && pseudoVersionRE.MatchString(v)
    }

go private

  • private时不会走proxy和checksumDB
    1
    2
    3
    4
    5
    6
    7
    // go/internal/modfetch/sumdb.go
    func useSumDB(mod module.Version) bool {
    return cfg.GOSUMDB != "off" && !module.MatchPrefixPatterns(cfg.GONOSUMDB, mod.Path) // cfg.GONOSUMDB里面包含了GOPRIVATE
    }

    // cmd/go/internal/cfg/cfg.go
    GONOSUMDB = envOr("GONOSUMDB", GOPRIVATE)

@latest

  • v0.0.5 > v0.0.5-alpha > v0.0.4
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // 版本比较的源码: src/cmd/vendor/golang.org/x/mod/semver/semver.go
    func Compare(v, w string) int {
    pv, ok1 := parse(v)
    pw, ok2 := parse(w)
    if !ok1 && !ok2 {
    return 0
    }
    if !ok1 {
    return -1
    }
    if !ok2 {
    return +1
    }
    if c := compareInt(pv.major, pw.major); c != 0 {
    return c
    }
    if c := compareInt(pv.minor, pw.minor); c != 0 {
    return c
    }
    if c := compareInt(pv.patch, pw.patch); c != 0 {
    return c
    }
    return comparePrerelease(pv.prerelease, pw.prerelease)
    }

indirect

  • main依赖了A, 但是A依赖了B但go.mod里没有require B, 则A的go.mod会自动加上B indirect
    • 此时main的go.mod强行require上B, 则B indirect将消失

exclude

  • 跳过某个版本 (之后一般gomod会自动使用比跳过版本更高的版本)
  • 例如: “require github.com/google/uuid v1.1.0”, 最后tidy后require里自动变成”github.com/google/uuid v1.1.1”
  • 跟replace一样, 仅main module时生效
  • 不大实用, 一般直接用replace即可

url

go.sum

commit version

  • go get github.com/pingcap/parser@659821e
  • go get github.com/pingcap/parser@latest
  • go get github.com/pingcap/parser@feature-lstest