git-lfs/config/filesystem.go

119 lines
3.4 KiB
Go
Raw Normal View History

package config
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
2016-11-15 17:01:18 +00:00
"github.com/git-lfs/git-lfs/git"
"github.com/git-lfs/git-lfs/tools"
"github.com/rubyist/tracerx"
)
var (
2017-10-19 00:35:03 +00:00
LocalReferenceDir string // alternative local media dir (relative to clone reference repo)
)
type fs struct {
WorkingDir string
GitDir string // parent of index / config / hooks etc
GitStorageDir string // parent of objects/lfs (may be same as LocalGitDir but may not)
ReferenceDir string // alternative local media dir (relative to clone reference repo)
LogDir string
}
2017-10-19 00:25:41 +00:00
func (f *fs) InRepo() bool {
if f == nil {
return false
}
return len(f.GitDir) > 0
}
// Determins the LocalWorkingDir, LocalGitDir etc
func resolveGitBasicDirs() *fs {
2017-10-19 00:35:03 +00:00
localGitDir, localWorkingDir, err := git.GitAndRootDirs()
if err != nil {
errMsg := err.Error()
tracerx.Printf("Error running 'git rev-parse': %s", errMsg)
if !strings.Contains(errMsg, "Not a git repository") {
fmt.Fprintf(os.Stderr, "Error: %s\n", errMsg)
}
return &fs{}
}
2017-10-19 00:35:03 +00:00
// Make sure we've fully evaluated symlinks, failure to do consistently
// can cause discrepancies
localGitDir = tools.ResolveSymlinks(localGitDir)
localWorkingDir = tools.ResolveSymlinks(localWorkingDir)
localGitStorageDir := resolveGitStorageDir(localGitDir)
LocalReferenceDir = resolveReferenceDir(localGitStorageDir)
return &fs{
GitDir: localGitDir,
WorkingDir: localWorkingDir,
GitStorageDir: localGitStorageDir,
ReferenceDir: LocalReferenceDir,
}
}
func resolveReferenceDir(gitStorageDir string) string {
cloneReferencePath := filepath.Join(gitStorageDir, "objects", "info", "alternates")
if tools.FileExists(cloneReferencePath) {
buffer, err := ioutil.ReadFile(cloneReferencePath)
if err == nil {
path := strings.TrimSpace(string(buffer[:]))
referenceLfsStoragePath := filepath.Join(filepath.Dir(path), "lfs", "objects")
if tools.DirExists(referenceLfsStoragePath) {
return referenceLfsStoragePath
}
}
}
return ""
}
// From a git dir, get the location that objects are to be stored (we will store lfs alongside)
// Sometimes there is an additional level of redirect on the .git folder by way of a commondir file
// before you find object storage, e.g. 'git worktree' uses this. It redirects to gitdir either by GIT_DIR
// (during setup) or .git/git-dir: (during use), but this only contains the index etc, the objects
// are found in another git dir via 'commondir'.
func resolveGitStorageDir(gitDir string) string {
commondirpath := filepath.Join(gitDir, "commondir")
if tools.FileExists(commondirpath) && !tools.DirExists(filepath.Join(gitDir, "objects")) {
// no git-dir: prefix in commondir
storage, err := processGitRedirectFile(commondirpath, "")
if err == nil {
return storage
}
}
return gitDir
}
func processGitRedirectFile(file, prefix string) (string, error) {
data, err := ioutil.ReadFile(file)
if err != nil {
return "", err
}
contents := string(data)
var dir string
if len(prefix) > 0 {
if !strings.HasPrefix(contents, prefix) {
// Prefix required & not found
return "", nil
}
dir = strings.TrimSpace(contents[len(prefix):])
} else {
dir = strings.TrimSpace(contents)
}
if !filepath.IsAbs(dir) {
// The .git file contains a relative path.
// Create an absolute path based on the directory the .git file is located in.
dir = filepath.Join(filepath.Dir(file), dir)
}
return dir, nil
}