mirror of https://github.com/kubernetes/kops.git
120 lines
3.4 KiB
Go
120 lines
3.4 KiB
Go
// Copyright 2024 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package modindex contains code for building and searching an
|
|
// [Index] of the Go module cache.
|
|
package modindex
|
|
|
|
// The directory containing the index, returned by
|
|
// [IndexDir], contains a file index-name-<ver> that contains the name
|
|
// of the current index. We believe writing that short file is atomic.
|
|
// [Read] reads that file to get the file name of the index.
|
|
// WriteIndex writes an index with a unique name and then
|
|
// writes that name into a new version of index-name-<ver>.
|
|
// (<ver> stands for the CurrentVersion of the index format.)
|
|
|
|
import (
|
|
"maps"
|
|
"os"
|
|
"path/filepath"
|
|
"slices"
|
|
"strings"
|
|
"time"
|
|
|
|
"golang.org/x/mod/semver"
|
|
)
|
|
|
|
// Update updates the index for the specified Go
|
|
// module cache directory, creating it as needed.
|
|
// On success it returns the current index.
|
|
func Update(gomodcache string) (*Index, error) {
|
|
prev, err := Read(gomodcache)
|
|
if err != nil {
|
|
if !os.IsNotExist(err) {
|
|
return nil, err
|
|
}
|
|
prev = nil
|
|
}
|
|
return update(gomodcache, prev)
|
|
}
|
|
|
|
// update builds, writes, and returns the current index.
|
|
//
|
|
// If old is nil, the new index is built from all of GOMODCACHE;
|
|
// otherwise it is built from the old index plus cache updates
|
|
// since the previous index's time.
|
|
func update(gomodcache string, old *Index) (*Index, error) {
|
|
gomodcache, err := filepath.Abs(gomodcache)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
new, changed, err := build(gomodcache, old)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if old == nil || changed {
|
|
if err := write(gomodcache, new); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return new, nil
|
|
}
|
|
|
|
// build returns a new index for the specified Go module cache (an
|
|
// absolute path).
|
|
//
|
|
// If an old index is provided, only directories more recent than it
|
|
// that it are scanned; older directories are provided by the old
|
|
// Index.
|
|
//
|
|
// The boolean result indicates whether new entries were found.
|
|
func build(gomodcache string, old *Index) (*Index, bool, error) {
|
|
// Set the time window.
|
|
var start time.Time // = dawn of time
|
|
if old != nil {
|
|
start = old.ValidAt
|
|
}
|
|
now := time.Now()
|
|
end := now.Add(24 * time.Hour) // safely in the future
|
|
|
|
// Enumerate GOMODCACHE package directories.
|
|
// Choose the best (latest) package for each import path.
|
|
pkgDirs := findDirs(gomodcache, start, end)
|
|
dirByPath, err := bestDirByImportPath(pkgDirs)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
// For each import path it might occur only in
|
|
// dirByPath, only in old, or in both.
|
|
// If both, use the semantically later one.
|
|
var entries []Entry
|
|
if old != nil {
|
|
for _, entry := range old.Entries {
|
|
dir, ok := dirByPath[entry.ImportPath]
|
|
if !ok || semver.Compare(dir.version, entry.Version) <= 0 {
|
|
// New dir is missing or not more recent; use old entry.
|
|
entries = append(entries, entry)
|
|
delete(dirByPath, entry.ImportPath)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Extract symbol information for all the new directories.
|
|
newEntries := extractSymbols(gomodcache, maps.Values(dirByPath))
|
|
entries = append(entries, newEntries...)
|
|
slices.SortFunc(entries, func(x, y Entry) int {
|
|
if n := strings.Compare(x.PkgName, y.PkgName); n != 0 {
|
|
return n
|
|
}
|
|
return strings.Compare(x.ImportPath, y.ImportPath)
|
|
})
|
|
|
|
return &Index{
|
|
GOMODCACHE: gomodcache,
|
|
ValidAt: now, // time before the directories were scanned
|
|
Entries: entries,
|
|
}, len(newEntries) > 0, nil
|
|
}
|