blob: 55bb334e4f6ade93536c1f548e8666a944b1a781 [file] [log] [blame]
// Copyright 2017 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 godata loads the Go project's corpus of Git, Github, and
// Gerrit activity into memory to allow easy analysis without worrying
// about APIs and their pagination, quotas, and other nuisances and
// limitations.
package godata
import (
"context"
"log"
"os"
"os/user"
"path/filepath"
"runtime"
"golang.org/x/build/maintner"
)
// Server is the Go project's production maintner log.
const Server = "https://maintner.golang.org/logs"
// Get returns the Go project's corpus, containing all Git commits,
// Github activity, and Gerrit activity and metadata since the
// beginning of the project.
//
// Use Corpus.Update to keep the corpus up-to-date. If you do this, you must
// hold the read lock if reading and updating concurrently.
//
// The initial call to Get will download a few gigabytes of data
// into a directory "golang-maintner" under your operating
// system's user cache directory. Subsequent calls will only download
// what's changed since the previous call.
//
// Even with all the data already cached on local disk, a call to Get
// takes approximately 15 seconds per gigabyte of mutation log data
// to load it into memory.
// For daemons, use Corpus.Update to incrementally update an
// already-loaded Corpus.
//
// The in-memory representation is about 25% larger than its on-disk
// size. In April 2022, it's under 4 GB.
//
// See https://pkg.go.dev/golang.org/x/build/maintner#Corpus for how
// to walk the data structure.
func Get(ctx context.Context) (*maintner.Corpus, error) {
targetDir := Dir()
if err := os.MkdirAll(targetDir, 0700); err != nil {
return nil, err
}
mutSrc := maintner.NewNetworkMutationSource(Server, targetDir)
corpus := new(maintner.Corpus)
if err := corpus.Initialize(ctx, mutSrc); err != nil {
return nil, err
}
return corpus, nil
}
// Dir returns the directory containing the cached mutation logs.
func Dir() string {
return filepath.Join(XdgCacheDir(), "golang-maintner")
}
// XdgCacheDir returns the XDG Base Directory Specification cache
// directory.
func XdgCacheDir() string {
cache := os.Getenv("XDG_CACHE_HOME")
if cache != "" {
return cache
}
home := homeDir()
// Not XDG but standard for OS X.
if runtime.GOOS == "darwin" {
return filepath.Join(home, "Library/Caches")
}
return filepath.Join(home, ".cache")
}
func homeDir() string {
if runtime.GOOS == "windows" {
return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
}
home := os.Getenv("HOME")
if home != "" {
return home
}
u, err := user.Current()
if err != nil {
log.Fatalf("failed to get home directory or current user: %v", err)
}
return u.HomeDir
}