golang.org/x/build@v0.0.0-20240506185731-218518f32b70/maintner/godata/godata.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package godata loads the Go project's corpus of Git, Github, and
     6  // Gerrit activity into memory to allow easy analysis without worrying
     7  // about APIs and their pagination, quotas, and other nuisances and
     8  // limitations.
     9  package godata
    10  
    11  import (
    12  	"context"
    13  	"log"
    14  	"os"
    15  	"os/user"
    16  	"path/filepath"
    17  	"runtime"
    18  
    19  	"golang.org/x/build/maintner"
    20  )
    21  
    22  // Server is the Go project's production maintner log.
    23  const Server = "https://maintner.golang.org/logs"
    24  
    25  // Get returns the Go project's corpus, containing all Git commits,
    26  // Github activity, and Gerrit activity and metadata since the
    27  // beginning of the project.
    28  //
    29  // Use Corpus.Update to keep the corpus up-to-date. If you do this, you must
    30  // hold the read lock if reading and updating concurrently.
    31  //
    32  // The initial call to Get will download a few gigabytes of data
    33  // into a directory "golang-maintner" under your operating
    34  // system's user cache directory. Subsequent calls will only download
    35  // what's changed since the previous call.
    36  //
    37  // Even with all the data already cached on local disk, a call to Get
    38  // takes approximately 15 seconds per gigabyte of mutation log data
    39  // to load it into memory.
    40  // For daemons, use Corpus.Update to incrementally update an
    41  // already-loaded Corpus.
    42  //
    43  // The in-memory representation is about 25% larger than its on-disk
    44  // size. In April 2022, it's under 4 GB.
    45  //
    46  // See https://pkg.go.dev/golang.org/x/build/maintner#Corpus for how
    47  // to walk the data structure.
    48  func Get(ctx context.Context) (*maintner.Corpus, error) {
    49  	targetDir := Dir()
    50  	if err := os.MkdirAll(targetDir, 0700); err != nil {
    51  		return nil, err
    52  	}
    53  	mutSrc := maintner.NewNetworkMutationSource(Server, targetDir)
    54  	corpus := new(maintner.Corpus)
    55  	if err := corpus.Initialize(ctx, mutSrc); err != nil {
    56  		return nil, err
    57  	}
    58  	return corpus, nil
    59  }
    60  
    61  // Dir returns the directory containing the cached mutation logs.
    62  func Dir() string {
    63  	return filepath.Join(XdgCacheDir(), "golang-maintner")
    64  }
    65  
    66  // XdgCacheDir returns the XDG Base Directory Specification cache
    67  // directory.
    68  func XdgCacheDir() string {
    69  	cache := os.Getenv("XDG_CACHE_HOME")
    70  	if cache != "" {
    71  		return cache
    72  	}
    73  	home := homeDir()
    74  	// Not XDG but standard for OS X.
    75  	if runtime.GOOS == "darwin" {
    76  		return filepath.Join(home, "Library/Caches")
    77  	}
    78  	return filepath.Join(home, ".cache")
    79  }
    80  
    81  func homeDir() string {
    82  	if runtime.GOOS == "windows" {
    83  		return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
    84  	}
    85  	home := os.Getenv("HOME")
    86  	if home != "" {
    87  		return home
    88  	}
    89  	u, err := user.Current()
    90  	if err != nil {
    91  		log.Fatalf("failed to get home directory or current user: %v", err)
    92  	}
    93  	return u.HomeDir
    94  }