Dependancy Management with go.mod

#Reading

#go mod

# go mod <command> [arguments]
go mod init <name>
# Updates all dependencies to lastest minor.patch version. (https://stackoverflow.com/q/66753231)
go get -u ./...

# vendore deps
go mod vendor

# update dependency (to minor.patch)
go get -u <url>

# why we have this dependency?
go mod why github.com/sirupsen/logrus
go mod graph | grep logrus

# editing
# remove from require
go mod edit -droprequire github.com/sirupsen/logrus
# add to repalce block
go mod edit -replace github.com/sirupsen/logrus=./logrus/local

# Dependencies
# downlaod missing
go mod tidy

# verify dependencies have expected content
go mod verify

#Troubleshooting

If case if go mod why useless, first resolve all go.mod versions on dependecies, then find what uses it.

# - ./dependancies/check_go_mod.py - 
##!/usr/bin/env -S uv run --script

# /// script
# dependencies = [ 'rich' ]
# ///

import asyncio
import pathlib
import re

from rich.console import Console
from rich.table import Table

go_version = re.compile(r"go (.*?)$", re.MULTILINE | re.DOTALL)

def get_go_mod_path(path: pathlib.Path) -> str | None:
    if not path.exists():
        return None

    return str(path)


def get_go_mod_version(path: pathlib.Path) -> str | None:
    if m := go_version.search(path.read_text()):
        return m.group(1)

    return None


async def main():
    root = pathlib.Path(".")
    home = pathlib.Path.home() / "go/pkg/mod"

    table = Table(title="Star Wars Movies")
    table.add_column("Package", justify="right", style="magenta")
    table.add_column("Version", style="cyan")
    table.add_column("Path go.mod", style="cyan")
    table.add_column("Version go.mod", style="cyan")

    goMod = root / "go.mod"
    pattern = re.compile(r"require \((.*?)\)$", re.MULTILINE | re.DOTALL)

    for req in pattern.findall(goMod.read_text()):
        for req in req.strip().splitlines():
            parts = req.split("//")[0].split()

            if len(parts) == 2:
                package, version = parts

                suffixes = package.split("/")

                pathToGoMod = home / f"{'/'.join(suffixes[:-1])}/{suffixes[-1]}@{version}/go.mod"

                path, goVersion = None, None
                if _path := get_go_mod_path(pathToGoMod):
                    path = _path
                    if _version := get_go_mod_version(pathToGoMod):
                        goVersion = _version

                table.add_row(package, version, path, goVersion)

    console = Console()
    console.print(table)


if __name__ == "__main__":
    asyncio.run(main())
# Then find whats uses this dependency.
cd ~/go/pkg && grep -R "github.com/user/pkg"

#GOPROXY

  • Using GOPRIVATE environment variable controls which modules the go command considers to be private (not available publicly).
  • Using GOPROXY environment variable we can tell what proxy for dependencies can be used.
  • GONOPROXY and GONOSUMDB environment variables accept the same kind of glob list and override GOPRIVATE for the specific decision of whether to use the proxy and checksum database, respectively.

#Resources

https://go.dev/wiki/GoGetProxyConfig https://jfrog.com/blog/why-goproxy-matters-and-which-to-pick/

#Vendoring

We can save all our dependecies with go mod vendor.

# wouln't work with go.work, need to turn it off with GOWORK=off
GOWORK=off go mod vendor