Imported Upstream version 2.3.3
[scm/test.git] / config / filesystem.go
1 package config
2
3 import (
4         "fmt"
5         "io/ioutil"
6         "os"
7         "path/filepath"
8         "strings"
9
10         "github.com/git-lfs/git-lfs/git"
11         "github.com/git-lfs/git-lfs/tools"
12         "github.com/rubyist/tracerx"
13 )
14
15 var (
16         LocalWorkingDir    string
17         LocalGitDir        string // parent of index / config / hooks etc
18         LocalGitStorageDir string // parent of objects/lfs (may be same as LocalGitDir but may not)
19         LocalReferenceDir  string // alternative local media dir (relative to clone reference repo)
20         LocalLogDir        string
21 )
22
23 // Determins the LocalWorkingDir, LocalGitDir etc
24 func ResolveGitBasicDirs() {
25         var err error
26         LocalGitDir, LocalWorkingDir, err = git.GitAndRootDirs()
27         if err == nil {
28                 // Make sure we've fully evaluated symlinks, failure to do consistently
29                 // can cause discrepancies
30                 LocalGitDir = tools.ResolveSymlinks(LocalGitDir)
31                 LocalWorkingDir = tools.ResolveSymlinks(LocalWorkingDir)
32
33                 LocalGitStorageDir = resolveGitStorageDir(LocalGitDir)
34                 LocalReferenceDir = resolveReferenceDir(LocalGitStorageDir)
35
36         } else {
37                 errMsg := err.Error()
38                 tracerx.Printf("Error running 'git rev-parse': %s", errMsg)
39                 if !strings.Contains(errMsg, "Not a git repository") {
40                         fmt.Fprintf(os.Stderr, "Error: %s\n", errMsg)
41                 }
42         }
43 }
44
45 func resolveReferenceDir(gitStorageDir string) string {
46         cloneReferencePath := filepath.Join(gitStorageDir, "objects", "info", "alternates")
47         if tools.FileExists(cloneReferencePath) {
48                 buffer, err := ioutil.ReadFile(cloneReferencePath)
49                 if err == nil {
50                         path := strings.TrimSpace(string(buffer[:]))
51                         referenceLfsStoragePath := filepath.Join(filepath.Dir(path), "lfs", "objects")
52                         if tools.DirExists(referenceLfsStoragePath) {
53                                 return referenceLfsStoragePath
54                         }
55                 }
56         }
57         return ""
58 }
59
60 // From a git dir, get the location that objects are to be stored (we will store lfs alongside)
61 // Sometimes there is an additional level of redirect on the .git folder by way of a commondir file
62 // before you find object storage, e.g. 'git worktree' uses this. It redirects to gitdir either by GIT_DIR
63 // (during setup) or .git/git-dir: (during use), but this only contains the index etc, the objects
64 // are found in another git dir via 'commondir'.
65 func resolveGitStorageDir(gitDir string) string {
66         commondirpath := filepath.Join(gitDir, "commondir")
67         if tools.FileExists(commondirpath) && !tools.DirExists(filepath.Join(gitDir, "objects")) {
68                 // no git-dir: prefix in commondir
69                 storage, err := processGitRedirectFile(commondirpath, "")
70                 if err == nil {
71                         return storage
72                 }
73         }
74         return gitDir
75 }
76
77 func processGitRedirectFile(file, prefix string) (string, error) {
78         data, err := ioutil.ReadFile(file)
79         if err != nil {
80                 return "", err
81         }
82
83         contents := string(data)
84         var dir string
85         if len(prefix) > 0 {
86                 if !strings.HasPrefix(contents, prefix) {
87                         // Prefix required & not found
88                         return "", nil
89                 }
90                 dir = strings.TrimSpace(contents[len(prefix):])
91         } else {
92                 dir = strings.TrimSpace(contents)
93         }
94
95         if !filepath.IsAbs(dir) {
96                 // The .git file contains a relative path.
97                 // Create an absolute path based on the directory the .git file is located in.
98                 dir = filepath.Join(filepath.Dir(file), dir)
99         }
100
101         return dir, nil
102 }