Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7,079 changes: 1,770 additions & 5,309 deletions DEPS.bzl

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ generate_grafana_scripts:
bazel_ci_prepare:
bazel $(BAZEL_GLOBAL_CONFIG) run $(BAZEL_CMD_CONFIG) //:gazelle
bazel $(BAZEL_GLOBAL_CONFIG) run $(BAZEL_CMD_CONFIG) //:gazelle -- update-repos -from_file=go.mod -to_macro DEPS.bzl%go_deps -build_file_proto_mode=disable -prune
bazel $(BAZEL_GLOBAL_CONFIG) run $(BAZEL_CMD_CONFIG) //cmd/mirror:mirror -- --mirror> tmp.txt
bazel $(BAZEL_GLOBAL_CONFIG) run $(BAZEL_CMD_CONFIG) //cmd/mirror:mirror > tmp.txt
mv tmp.txt DEPS.bzl
bazel $(BAZEL_GLOBAL_CONFIG) run $(BAZEL_CMD_CONFIG) \
--run_under="cd $(CURDIR) && " \
Expand All @@ -684,7 +684,7 @@ bazel_prepare: ## Update and generate BUILD.bazel files. Please run this before
--run_under="cd $(CURDIR) && " \
//tools/tazel:tazel
$(eval $@TMP_OUT := $(shell mktemp -d -t tidbbzl.XXXXXX))
bazel $(BAZEL_GLOBAL_CONFIG) run $(BAZEL_CMD_CONFIG) //cmd/mirror -- --mirror> $($@TMP_OUT)/tmp.txt
bazel $(BAZEL_GLOBAL_CONFIG) run $(BAZEL_CMD_CONFIG) //cmd/mirror > $($@TMP_OUT)/tmp.txt
cp $($@TMP_OUT)/tmp.txt DEPS.bzl
rm -rf $($@TMP_OUT)

Expand Down Expand Up @@ -919,7 +919,7 @@ docker-test:
.PHONY: bazel_mirror
bazel_mirror:
$(eval $@TMP_OUT := $(shell mktemp -d -t tidbbzl.XXXXXX))
bazel $(BAZEL_GLOBAL_CONFIG) run $(BAZEL_CMD_CONFIG) --norun_validations //cmd/mirror:mirror -- --mirror> $($@TMP_OUT)/tmp.txt
bazel $(BAZEL_GLOBAL_CONFIG) run $(BAZEL_CMD_CONFIG) --norun_validations //cmd/mirror:mirror > $($@TMP_OUT)/tmp.txt
cp $($@TMP_OUT)/tmp.txt DEPS.bzl
rm -rf $($@TMP_OUT)

Expand All @@ -929,7 +929,7 @@ bazel_sync:

.PHONY: bazel_mirror_upload
bazel_mirror_upload:
bazel $(BAZEL_GLOBAL_CONFIG) run $(BAZEL_CMD_CONFIG) --norun_validations //cmd/mirror -- --mirror --upload
@echo "bazel_mirror_upload is deprecated; Go modules are resolved through GOPROXY. Run 'make bazel_mirror' to regenerate DEPS.bzl."

.PHONY: bazel_check_abi
bazel_check_abi:
Expand Down
9 changes: 1 addition & 8 deletions cmd/mirror/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,11 @@ load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")

go_library(
name = "mirror_lib",
srcs = [
"mirror.go",
"skylarkutil.go",
],
srcs = ["mirror.go"],
importpath = "github.com/pingcap/tidb/cmd/mirror",
visibility = ["//visibility:private"],
deps = [
"@com_github_google_skylark//syntax",
"@com_google_cloud_go_storage//:storage",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
"@org_golang_google_api//googleapi",
"@org_golang_x_sync//errgroup",
],
)

Expand Down
173 changes: 20 additions & 153 deletions cmd/mirror/mirror.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,20 @@
package main

import (
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"path/filepath"
"slices"
"sort"
"strings"

"cloud.google.com/go/storage"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"golang.org/x/sync/errgroup"
"google.golang.org/api/googleapi"
)

const gcpBucket = "pingcapmirror"

// downloadedModule captures `go mod download -json` output.
type downloadedModule struct {
Path string `json:"Path"`
Expand All @@ -60,33 +50,8 @@ var (
)

func init() {
flag.BoolVar(&isMirror, "mirror", false, "enable mirror mode")
flag.BoolVar(&isUpload, "upload", false, "enable upload mode")
}

func formatSubURL(path, version string) string {
return fmt.Sprintf("gomod/%s/%s-%s.zip", path, modulePathToBazelRepoName(path), version)
}

func formatCDNURL(path, version string) string {
return fmt.Sprintf("https://cache.hawkingrei.com/%s", formatSubURL(path, version))
}

func formatPublicURL(path, version string) string {
return fmt.Sprintf("https://storage.googleapis.com/pingcapmirror/%s", formatSubURL(path, version))
}

func getSha256OfFile(path string) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", fmt.Errorf("failed to open %s: %w", path, err)
}
defer f.Close()
h := sha256.New()
if _, err := io.Copy(h, f); err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
flag.BoolVar(&isMirror, "mirror", false, "deprecated; ignored")
flag.BoolVar(&isUpload, "upload", false, "deprecated; ignored")
}

func copyFile(src, dst string) error {
Expand All @@ -104,34 +69,6 @@ func copyFile(src, dst string) error {
return err
}

func uploadFile(ctx context.Context, client *storage.Client, localPath, remotePath string) error {
if !isUpload {
return nil
}
in, err := os.Open(localPath)
if err != nil {
return fmt.Errorf("failed to open %s: %w", localPath, err)
}
defer in.Close()
out := client.Bucket(gcpBucket).Object(remotePath).If(storage.Conditions{DoesNotExist: true}).NewWriter(ctx)
if _, err := io.Copy(out, in); err != nil {
return err
}
if err := out.Close(); err != nil {
var gerr *googleapi.Error
if errors.As(err, &gerr) {
if gerr.Code == http.StatusPreconditionFailed {
// In this case the "DoesNotExist" precondition
// failed, i.e., the object does already exist.
return nil
}
return gerr
}
return err
}
return nil
}

func createTmpDir() (tmpdir string, err error) {
tmpdir, err = bazel.NewTmpDir("gomirror")
if err != nil {
Expand Down Expand Up @@ -244,14 +181,6 @@ func listAllModules(tmpdir string) (map[string]listedModule, error) {
return ret, nil
}

func getExistingMirrors() (map[string]DownloadableArtifact, error) {
depsbzl, err := bazel.Runfile("DEPS.bzl")
if err != nil {
return nil, err
}
return ListArtifactsInDepsBzl(depsbzl)
}

func mungeBazelRepoNameComponent(component string) string {
component = strings.ReplaceAll(component, "-", "_")
component = strings.ReplaceAll(component, ".", "_")
Expand Down Expand Up @@ -307,7 +236,6 @@ func dumpBuildNamingConventionArgsForRepo(repoName string) {
func dumpNewDepsBzl(
listed map[string]listedModule,
downloaded map[string]downloadedModule,
existingMirrors map[string]DownloadableArtifact,
) error {
var sorted []string
repoNameToModPath := make(map[string]string)
Expand All @@ -318,19 +246,8 @@ func dumpNewDepsBzl(
}
sort.Strings(sorted)

ctx := context.Background()
var client *storage.Client
if isMirror && isUpload {
var err error
client, err = storage.NewClient(ctx)
if err != nil {
return err
}
}
g, ctx := errgroup.WithContext(ctx)

// This uses a lot of fmt.Println to output the generated configuration to stdout,
// and the mirror will only be used under "make bazel_prepare", so it won't output
// and the generator will only be used under "make bazel_prepare", so it won't output
// too much and affect development.
fmt.Println(`load("@bazel_gazelle//:deps.bzl", "go_repository")

Expand Down Expand Up @@ -358,75 +275,23 @@ def go_deps():
fmt.Printf(` build_file_proto_mode = "%s",
`, buildFileProtoModeForRepo(repoName))
dumpBuildNamingConventionArgsForRepo(repoName)
expectedCDNURL := formatCDNURL(replaced.Path, replaced.Version)
expectedPublicURL := formatPublicURL(replaced.Path, replaced.Version)
fmt.Printf(" importpath = \"%s\",\n", mod.Path)
if err := dumpPatchArgsForRepo(repoName); err != nil {
return err
}
oldMirror, ok := existingMirrors[repoName]
if ok &&
slices.Contains(oldMirror.URL, expectedCDNURL) &&
slices.Contains(oldMirror.URL, expectedPublicURL) {
// The URL matches, so just reuse the old mirror.
fmt.Printf(` sha256 = "%s",
strip_prefix = "%s@%s",
urls = [
"%s",
"%s",
],
`, oldMirror.Sha256, replaced.Path, replaced.Version, expectedCDNURL, expectedPublicURL)
} else if isMirror {
// We'll have to mirror our copy of the zip ourselves.
d := downloaded[replaced.Path]
sha, err := getSha256OfFile(d.Zip)
if err != nil {
return fmt.Errorf("could not get zip for %v: %w", *replaced, err)
}
if sha == "30cf0ef9aa63aea696e40df8912d41fbce69dd02986a5b99af7c5b75f277690c" {
sha = "ebe8386761761d53fac2de5f8f575ddf66c114ec9835947c761131662f1d38f3"
}
fmt.Printf(` sha256 = "%s",
strip_prefix = "%s@%s",
urls = [
"%s",
"%s",
],
`, sha, replaced.Path, replaced.Version, expectedCDNURL, expectedPublicURL)
g.Go(func() error {
return uploadFile(ctx, client, d.Zip, formatSubURL(replaced.Path, replaced.Version))
})
} else {
// We don't have a mirror and can't upload one, so just
// have Gazelle pull the repo for us.
d := downloaded[replaced.Path]
sum, version := d.Sum, d.Version
if mod.Replace != nil {
fmt.Printf(" replace = \"%s\",\n", replaced.Path)
}
artifact, ok := existingMirrors[replaced.Path]
if ok {
sum, version = artifact.Sha256, artifact.Version
}
// Note: `build/teamcity-check-genfiles.sh` checks for
// the presence of the "TODO: mirror this repo" comment.
// Don't update this comment without also updating the
// script.
fmt.Printf(` sum = "%s",
version = "%s",
`, sum, version)
d, ok := downloaded[replaced.Path]
if !ok {
return fmt.Errorf("could not find downloaded module for %s@%s", replaced.Path, replaced.Version)
}
if mod.Replace != nil {
fmt.Printf(" replace = \"%s\",\n", replaced.Path)
}
fmt.Printf(` sum = "%s",
version = "%s",
`, d.Sum, d.Version)
Comment on lines +282 to +291

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find any replace directives, highlighting local-path (no version) replaces
rg -n '=>' go.mod pkg/parser/go.mod || echo "no replace directives found"

Repository: pingcap/tidb

Length of output: 680


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the generator logic around downloadZips and dumpNewDepsBzl.
ast-grep outline cmd/mirror/mirror.go --view expanded

printf '\n--- relevant slices ---\n'
sed -n '90,160p' cmd/mirror/mirror.go
printf '\n---\n'
sed -n '250,320p' cmd/mirror/mirror.go

printf '\n--- replace handling in go.mod / parser go.mod context ---\n'
rg -n '^\s*replace\s+|=>\s+\.{1,2}/|=>\s+\./' go.mod pkg/parser/go.mod

Repository: pingcap/tidb

Length of output: 5229


Handle local-path replaces in dumpNewDepsBzl
go.mod already has github.com/pingcap/tidb/pkg/parser => ./pkg/parser, and downloadZips skips local-path replaces while dumpNewDepsBzl still looks up downloaded[replaced.Path]. That makes make bazel_mirror fail on the current tree unless local replaces are skipped or handled explicitly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/mirror/mirror.go` around lines 282 - 291, Handle local-path replaces in
dumpNewDepsBzl: the current lookup of downloaded[replaced.Path] assumes every
replacement was downloaded, but local-path replaces like ./pkg/parser are
skipped by downloadZips and will not exist in that map. Update dumpNewDepsBzl
(around the replaced.Path / downloaded lookup logic) to either skip local-path
replacements explicitly or branch to handle them without requiring a downloaded
entry, while keeping the existing behavior for remote modules.

fmt.Println(" )")
}

// Wait for uploads to complete.
if err := g.Wait(); err != nil {
return err
}
if client == nil {
return nil
}
return client.Close()
return nil
}

func mirror() error {
Expand All @@ -448,15 +313,17 @@ func mirror() error {
if err != nil {
return err
}
existingMirrors, err := getExistingMirrors()
if err != nil {
return err
}
return dumpNewDepsBzl(listed, downloaded, existingMirrors)
return dumpNewDepsBzl(listed, downloaded)
}

func main() {
flag.Parse()
if isMirror {
fmt.Fprintln(os.Stderr, "--mirror is deprecated and ignored; modules are resolved through GOPROXY")
}
if isUpload {
fmt.Fprintln(os.Stderr, "--upload is deprecated and ignored; modules are resolved through GOPROXY")
}
if err := mirror(); err != nil {
var exitErr *exec.ExitError
if errors.As(err, &exitErr) {
Expand Down
Loading
Loading