зеркало из https://github.com/golang/dep.git
137 строки
2.9 KiB
Go
137 строки
2.9 KiB
Go
// 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 gps
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// fsLink represents a symbolic link.
|
|
type fsLink struct {
|
|
path string
|
|
to string
|
|
|
|
// circular denotes if evaluating the symlink fails with "too many links" error.
|
|
// This errors means that it's very likely that the symlink has circual refernce.
|
|
circular bool
|
|
|
|
// broken denotes that attempting to resolve the link fails, most likely because
|
|
// the destaination doesn't exist.
|
|
broken bool
|
|
}
|
|
|
|
// filesystemState represents the state of a file system.
|
|
type filesystemState struct {
|
|
root string
|
|
dirs []string
|
|
files []string
|
|
links []fsLink
|
|
}
|
|
|
|
func (s filesystemState) setup() error {
|
|
for _, dir := range s.dirs {
|
|
p := filepath.Join(s.root, dir)
|
|
|
|
if err := os.MkdirAll(p, 0777); err != nil {
|
|
return errors.Errorf("os.MkdirAll(%q, 0777) err=%q", p, err)
|
|
}
|
|
}
|
|
|
|
for _, file := range s.files {
|
|
p := filepath.Join(s.root, file)
|
|
|
|
f, err := os.Create(p)
|
|
if err != nil {
|
|
return errors.Errorf("os.Create(%q) err=%q", p, err)
|
|
}
|
|
|
|
if err := f.Close(); err != nil {
|
|
return errors.Errorf("file %q Close() err=%q", p, err)
|
|
}
|
|
}
|
|
|
|
for _, link := range s.links {
|
|
p := filepath.Join(s.root, link.path)
|
|
|
|
// On Windows, relative symlinks confuse filepath.Walk. So, we'll just sigh
|
|
// and do absolute links, assuming they are relative to the directory of
|
|
// link.path.
|
|
//
|
|
// Reference: https://github.com/golang/go/issues/17540
|
|
//
|
|
// TODO(ibrasho): This was fixed in Go 1.9. Remove this when support for
|
|
// 1.8 is dropped.
|
|
dir := filepath.Dir(p)
|
|
to := ""
|
|
if link.to != "" {
|
|
to = filepath.Join(dir, link.to)
|
|
}
|
|
|
|
if err := os.Symlink(to, p); err != nil {
|
|
return errors.Errorf("os.Symlink(%q, %q) err=%q", to, p, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// deriveFilesystemState returns a filesystemState based on the state of
|
|
// the filesystem on root.
|
|
func deriveFilesystemState(root string) (filesystemState, error) {
|
|
fs := filesystemState{root: root}
|
|
|
|
err := filepath.Walk(fs.root, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if path == fs.root {
|
|
return nil
|
|
}
|
|
|
|
relPath, err := filepath.Rel(fs.root, path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if (info.Mode() & os.ModeSymlink) != 0 {
|
|
l := fsLink{path: relPath}
|
|
|
|
l.to, err = filepath.EvalSymlinks(path)
|
|
if err != nil && strings.HasSuffix(err.Error(), "too many links") {
|
|
l.circular = true
|
|
} else if err != nil && os.IsNotExist(err) {
|
|
l.broken = true
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
|
|
fs.links = append(fs.links, l)
|
|
|
|
return nil
|
|
}
|
|
|
|
if info.IsDir() {
|
|
fs.dirs = append(fs.dirs, relPath)
|
|
|
|
return nil
|
|
}
|
|
|
|
fs.files = append(fs.files, relPath)
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return filesystemState{}, err
|
|
}
|
|
|
|
return fs, nil
|
|
}
|