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
5package cache
6
7import (
8	"fmt"
9	"io/ioutil"
10	"log"
11	"os"
12	"path/filepath"
13	"sync"
14)
15
16// Default returns the default cache to use.
17func Default() (*Cache, error) {
18	defaultOnce.Do(initDefaultCache)
19	return defaultCache, defaultDirErr
20}
21
22var (
23	defaultOnce  sync.Once
24	defaultCache *Cache
25)
26
27// cacheREADME is a message stored in a README in the cache directory.
28// Because the cache lives outside the normal Go trees, we leave the
29// README as a courtesy to explain where it came from.
30const cacheREADME = `This directory holds cached build artifacts from golangci-lint.
31`
32
33// initDefaultCache does the work of finding the default cache
34// the first time Default is called.
35func initDefaultCache() {
36	dir := DefaultDir()
37	if err := os.MkdirAll(dir, 0744); err != nil {
38		log.Fatalf("failed to initialize build cache at %s: %s\n", dir, err)
39	}
40	if _, err := os.Stat(filepath.Join(dir, "README")); err != nil {
41		// Best effort.
42		if wErr := ioutil.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666); wErr != nil {
43			log.Fatalf("Failed to write README file to cache dir %s: %s", dir, err)
44		}
45	}
46
47	c, err := Open(dir)
48	if err != nil {
49		log.Fatalf("failed to initialize build cache at %s: %s\n", dir, err)
50	}
51	defaultCache = c
52}
53
54var (
55	defaultDirOnce sync.Once
56	defaultDir     string
57	defaultDirErr  error
58)
59
60// DefaultDir returns the effective GOLANGCI_LINT_CACHE setting.
61func DefaultDir() string {
62	// Save the result of the first call to DefaultDir for later use in
63	// initDefaultCache. cmd/go/main.go explicitly sets GOCACHE so that
64	// subprocesses will inherit it, but that means initDefaultCache can't
65	// otherwise distinguish between an explicit "off" and a UserCacheDir error.
66
67	defaultDirOnce.Do(func() {
68		defaultDir = os.Getenv("GOLANGCI_LINT_CACHE")
69		if filepath.IsAbs(defaultDir) {
70			return
71		}
72		if defaultDir != "" {
73			defaultDirErr = fmt.Errorf("GOLANGCI_LINT_CACHE is not an absolute path")
74			return
75		}
76
77		// Compute default location.
78		dir, err := os.UserCacheDir()
79		if err != nil {
80			defaultDirErr = fmt.Errorf("GOLANGCI_LINT_CACHE is not defined and %v", err)
81			return
82		}
83		defaultDir = filepath.Join(dir, "golangci-lint")
84	})
85
86	return defaultDir
87}
88