vendor: github.com/spf13/afero@v1.2.1
go get github.com/spf13/afero@v1.2.1 go mod tidy go mod vendor
This commit is contained in:
parent
52b38a486a
commit
3d0b6bff07
2
go.mod
2
go.mod
|
@ -106,7 +106,7 @@ require (
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
|
||||||
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect
|
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect
|
||||||
github.com/soheilhy/cmux v0.1.4 // indirect
|
github.com/soheilhy/cmux v0.1.4 // indirect
|
||||||
github.com/spf13/afero v1.0.2
|
github.com/spf13/afero v1.2.1
|
||||||
github.com/terraform-providers/terraform-provider-openstack v1.15.0
|
github.com/terraform-providers/terraform-provider-openstack v1.15.0
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 // indirect
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 // indirect
|
||||||
github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5 // indirect
|
github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -358,8 +358,8 @@ github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||||
github.com/spf13/afero v1.0.2 h1:5bRmqmInNmNFkI9NG9O0Xc/Lgl9wOWWUUA/O8XZqTCo=
|
github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M=
|
||||||
github.com/spf13/afero v1.0.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc=
|
github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc=
|
||||||
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
|
|
@ -2,8 +2,8 @@ sudo: false
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.7.5
|
- 1.9
|
||||||
- 1.8
|
- "1.10"
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
os:
|
os:
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package afero
|
package afero
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -9,6 +8,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ Lstater = (*BasePathFs)(nil)
|
||||||
|
|
||||||
// The BasePathFs restricts all operations to a given path within an Fs.
|
// The BasePathFs restricts all operations to a given path within an Fs.
|
||||||
// The given file name to the operations on this Fs will be prepended with
|
// The given file name to the operations on this Fs will be prepended with
|
||||||
// the base path before calling the base Fs.
|
// the base path before calling the base Fs.
|
||||||
|
@ -22,6 +23,16 @@ type BasePathFs struct {
|
||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BasePathFile struct {
|
||||||
|
File
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *BasePathFile) Name() string {
|
||||||
|
sourcename := f.File.Name()
|
||||||
|
return strings.TrimPrefix(sourcename, filepath.Clean(f.path))
|
||||||
|
}
|
||||||
|
|
||||||
func NewBasePathFs(source Fs, path string) Fs {
|
func NewBasePathFs(source Fs, path string) Fs {
|
||||||
return &BasePathFs{source: source, path: path}
|
return &BasePathFs{source: source, path: path}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +41,7 @@ func NewBasePathFs(source Fs, path string) Fs {
|
||||||
// else the given file with the base path prepended
|
// else the given file with the base path prepended
|
||||||
func (b *BasePathFs) RealPath(name string) (path string, err error) {
|
func (b *BasePathFs) RealPath(name string) (path string, err error) {
|
||||||
if err := validateBasePathName(name); err != nil {
|
if err := validateBasePathName(name); err != nil {
|
||||||
return "", err
|
return name, err
|
||||||
}
|
}
|
||||||
|
|
||||||
bpath := filepath.Clean(b.path)
|
bpath := filepath.Clean(b.path)
|
||||||
|
@ -52,7 +63,7 @@ func validateBasePathName(name string) error {
|
||||||
// On Windows a common mistake would be to provide an absolute OS path
|
// On Windows a common mistake would be to provide an absolute OS path
|
||||||
// We could strip out the base part, but that would not be very portable.
|
// We could strip out the base part, but that would not be very portable.
|
||||||
if filepath.IsAbs(name) {
|
if filepath.IsAbs(name) {
|
||||||
return &os.PathError{Op: "realPath", Path: name, Err: errors.New("got a real OS path instead of a virtual")}
|
return os.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -111,14 +122,22 @@ func (b *BasePathFs) OpenFile(name string, flag int, mode os.FileMode) (f File,
|
||||||
if name, err = b.RealPath(name); err != nil {
|
if name, err = b.RealPath(name); err != nil {
|
||||||
return nil, &os.PathError{Op: "openfile", Path: name, Err: err}
|
return nil, &os.PathError{Op: "openfile", Path: name, Err: err}
|
||||||
}
|
}
|
||||||
return b.source.OpenFile(name, flag, mode)
|
sourcef, err := b.source.OpenFile(name, flag, mode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &BasePathFile{sourcef, b.path}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BasePathFs) Open(name string) (f File, err error) {
|
func (b *BasePathFs) Open(name string) (f File, err error) {
|
||||||
if name, err = b.RealPath(name); err != nil {
|
if name, err = b.RealPath(name); err != nil {
|
||||||
return nil, &os.PathError{Op: "open", Path: name, Err: err}
|
return nil, &os.PathError{Op: "open", Path: name, Err: err}
|
||||||
}
|
}
|
||||||
return b.source.Open(name)
|
sourcef, err := b.source.Open(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &BasePathFile{File: sourcef, path: b.path}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BasePathFs) Mkdir(name string, mode os.FileMode) (err error) {
|
func (b *BasePathFs) Mkdir(name string, mode os.FileMode) (err error) {
|
||||||
|
@ -139,7 +158,23 @@ func (b *BasePathFs) Create(name string) (f File, err error) {
|
||||||
if name, err = b.RealPath(name); err != nil {
|
if name, err = b.RealPath(name); err != nil {
|
||||||
return nil, &os.PathError{Op: "create", Path: name, Err: err}
|
return nil, &os.PathError{Op: "create", Path: name, Err: err}
|
||||||
}
|
}
|
||||||
return b.source.Create(name)
|
sourcef, err := b.source.Create(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &BasePathFile{File: sourcef, path: b.path}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BasePathFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
||||||
|
name, err := b.RealPath(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, &os.PathError{Op: "lstat", Path: name, Err: err}
|
||||||
|
}
|
||||||
|
if lstater, ok := b.source.(Lstater); ok {
|
||||||
|
return lstater.LstatIfPossible(name)
|
||||||
|
}
|
||||||
|
fi, err := b.source.Stat(name)
|
||||||
|
return fi, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: ts=4 sw=4 noexpandtab nolist syn=go
|
// vim: ts=4 sw=4 noexpandtab nolist syn=go
|
||||||
|
|
|
@ -205,7 +205,7 @@ func (u *CacheOnReadFs) OpenFile(name string, flag int, perm os.FileMode) (File,
|
||||||
bfi.Close() // oops, what if O_TRUNC was set and file opening in the layer failed...?
|
bfi.Close() // oops, what if O_TRUNC was set and file opening in the layer failed...?
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &UnionFile{base: bfi, layer: lfi}, nil
|
return &UnionFile{Base: bfi, Layer: lfi}, nil
|
||||||
}
|
}
|
||||||
return u.layer.OpenFile(name, flag, perm)
|
return u.layer.OpenFile(name, flag, perm)
|
||||||
}
|
}
|
||||||
|
@ -251,7 +251,7 @@ func (u *CacheOnReadFs) Open(name string) (File, error) {
|
||||||
if err != nil && bfile == nil {
|
if err != nil && bfile == nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &UnionFile{base: bfile, layer: lfile}, nil
|
return &UnionFile{Base: bfile, Layer: lfile}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CacheOnReadFs) Mkdir(name string, perm os.FileMode) error {
|
func (u *CacheOnReadFs) Mkdir(name string, perm os.FileMode) error {
|
||||||
|
@ -286,5 +286,5 @@ func (u *CacheOnReadFs) Create(name string) (File, error) {
|
||||||
bfh.Close()
|
bfh.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &UnionFile{base: bfh, layer: lfh}, nil
|
return &UnionFile{Base: bfh, Layer: lfh}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ Lstater = (*CopyOnWriteFs)(nil)
|
||||||
|
|
||||||
// The CopyOnWriteFs is a union filesystem: a read only base file system with
|
// The CopyOnWriteFs is a union filesystem: a read only base file system with
|
||||||
// a possibly writeable layer on top. Changes to the file system will only
|
// a possibly writeable layer on top. Changes to the file system will only
|
||||||
// be made in the overlay: Changing an existing file in the base layer which
|
// be made in the overlay: Changing an existing file in the base layer which
|
||||||
|
@ -76,16 +78,53 @@ func (u *CopyOnWriteFs) Chmod(name string, mode os.FileMode) error {
|
||||||
func (u *CopyOnWriteFs) Stat(name string) (os.FileInfo, error) {
|
func (u *CopyOnWriteFs) Stat(name string) (os.FileInfo, error) {
|
||||||
fi, err := u.layer.Stat(name)
|
fi, err := u.layer.Stat(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
origErr := err
|
isNotExist := u.isNotExist(err)
|
||||||
|
if isNotExist {
|
||||||
|
return u.base.Stat(name)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return fi, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CopyOnWriteFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
||||||
|
llayer, ok1 := u.layer.(Lstater)
|
||||||
|
lbase, ok2 := u.base.(Lstater)
|
||||||
|
|
||||||
|
if ok1 {
|
||||||
|
fi, b, err := llayer.LstatIfPossible(name)
|
||||||
|
if err == nil {
|
||||||
|
return fi, b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !u.isNotExist(err) {
|
||||||
|
return nil, b, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok2 {
|
||||||
|
fi, b, err := lbase.LstatIfPossible(name)
|
||||||
|
if err == nil {
|
||||||
|
return fi, b, nil
|
||||||
|
}
|
||||||
|
if !u.isNotExist(err) {
|
||||||
|
return nil, b, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := u.Stat(name)
|
||||||
|
|
||||||
|
return fi, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CopyOnWriteFs) isNotExist(err error) bool {
|
||||||
if e, ok := err.(*os.PathError); ok {
|
if e, ok := err.(*os.PathError); ok {
|
||||||
err = e.Err
|
err = e.Err
|
||||||
}
|
}
|
||||||
if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENOTDIR {
|
if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENOTDIR {
|
||||||
return u.base.Stat(name)
|
return true
|
||||||
}
|
}
|
||||||
return nil, origErr
|
return false
|
||||||
}
|
|
||||||
return fi, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renaming files present only in the base layer is not permitted
|
// Renaming files present only in the base layer is not permitted
|
||||||
|
@ -219,7 +258,7 @@ func (u *CopyOnWriteFs) Open(name string) (File, error) {
|
||||||
return nil, fmt.Errorf("BaseErr: %v\nOverlayErr: %v", bErr, lErr)
|
return nil, fmt.Errorf("BaseErr: %v\nOverlayErr: %v", bErr, lErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &UnionFile{base: bfile, layer: lfile}, nil
|
return &UnionFile{Base: bfile, Layer: lfile}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CopyOnWriteFs) Mkdir(name string, perm os.FileMode) error {
|
func (u *CopyOnWriteFs) Mkdir(name string, perm os.FileMode) error {
|
||||||
|
@ -228,7 +267,7 @@ func (u *CopyOnWriteFs) Mkdir(name string, perm os.FileMode) error {
|
||||||
return u.layer.MkdirAll(name, perm)
|
return u.layer.MkdirAll(name, perm)
|
||||||
}
|
}
|
||||||
if dir {
|
if dir {
|
||||||
return syscall.EEXIST
|
return ErrFileExists
|
||||||
}
|
}
|
||||||
return u.layer.MkdirAll(name, perm)
|
return u.layer.MkdirAll(name, perm)
|
||||||
}
|
}
|
||||||
|
@ -243,7 +282,8 @@ func (u *CopyOnWriteFs) MkdirAll(name string, perm os.FileMode) error {
|
||||||
return u.layer.MkdirAll(name, perm)
|
return u.layer.MkdirAll(name, perm)
|
||||||
}
|
}
|
||||||
if dir {
|
if dir {
|
||||||
return syscall.EEXIST
|
// This is in line with how os.MkdirAll behaves.
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return u.layer.MkdirAll(name, perm)
|
return u.layer.MkdirAll(name, perm)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/spf13/afero
|
||||||
|
|
||||||
|
require golang.org/x/text v0.3.0
|
|
@ -0,0 +1,2 @@
|
||||||
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright © 2018 Steve Francia <spf@spf13.com>.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package afero
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Lstater is an optional interface in Afero. It is only implemented by the
|
||||||
|
// filesystems saying so.
|
||||||
|
// It will call Lstat if the filesystem iself is, or it delegates to, the os filesystem.
|
||||||
|
// Else it will call Stat.
|
||||||
|
// In addtion to the FileInfo, it will return a boolean telling whether Lstat was called or not.
|
||||||
|
type Lstater interface {
|
||||||
|
LstatIfPossible(name string) (os.FileInfo, bool, error)
|
||||||
|
}
|
|
@ -33,8 +33,8 @@ import (
|
||||||
// built-ins from that package.
|
// built-ins from that package.
|
||||||
func Glob(fs Fs, pattern string) (matches []string, err error) {
|
func Glob(fs Fs, pattern string) (matches []string, err error) {
|
||||||
if !hasMeta(pattern) {
|
if !hasMeta(pattern) {
|
||||||
// afero does not support Lstat directly.
|
// Lstat not supported by a ll filesystems.
|
||||||
if _, err = lstatIfOs(fs, pattern); err != nil {
|
if _, err = lstatIfPossible(fs, pattern); err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return []string{pattern}, nil
|
return []string{pattern}, nil
|
||||||
|
|
|
@ -131,6 +131,9 @@ func (f *File) Sync() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) Readdir(count int) (res []os.FileInfo, err error) {
|
func (f *File) Readdir(count int) (res []os.FileInfo, err error) {
|
||||||
|
if !f.fileData.dir {
|
||||||
|
return nil, &os.PathError{Op: "readdir", Path: f.fileData.name, Err: errors.New("not a dir")}
|
||||||
|
}
|
||||||
var outLength int64
|
var outLength int64
|
||||||
|
|
||||||
f.fileData.Lock()
|
f.fileData.Lock()
|
||||||
|
|
|
@ -19,6 +19,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ Lstater = (*OsFs)(nil)
|
||||||
|
|
||||||
// OsFs is a Fs implementation that uses functions provided by the os package.
|
// OsFs is a Fs implementation that uses functions provided by the os package.
|
||||||
//
|
//
|
||||||
// For details in any method, check the documentation of the os package
|
// For details in any method, check the documentation of the os package
|
||||||
|
@ -92,3 +94,8 @@ func (OsFs) Chmod(name string, mode os.FileMode) error {
|
||||||
func (OsFs) Chtimes(name string, atime time.Time, mtime time.Time) error {
|
func (OsFs) Chtimes(name string, atime time.Time, mtime time.Time) error {
|
||||||
return os.Chtimes(name, atime, mtime)
|
return os.Chtimes(name, atime, mtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (OsFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
||||||
|
fi, err := os.Lstat(name)
|
||||||
|
return fi, true, err
|
||||||
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ func walk(fs Fs, path string, info os.FileInfo, walkFn filepath.WalkFunc) error
|
||||||
|
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
filename := filepath.Join(path, name)
|
filename := filepath.Join(path, name)
|
||||||
fileInfo, err := lstatIfOs(fs, filename)
|
fileInfo, err := lstatIfPossible(fs, filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
|
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
|
||||||
return err
|
return err
|
||||||
|
@ -77,15 +77,13 @@ func walk(fs Fs, path string, info os.FileInfo, walkFn filepath.WalkFunc) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the filesystem is OsFs use Lstat, else use fs.Stat
|
// if the filesystem supports it, use Lstat, else use fs.Stat
|
||||||
func lstatIfOs(fs Fs, path string) (info os.FileInfo, err error) {
|
func lstatIfPossible(fs Fs, path string) (os.FileInfo, error) {
|
||||||
_, ok := fs.(*OsFs)
|
if lfs, ok := fs.(Lstater); ok {
|
||||||
if ok {
|
fi, _, err := lfs.LstatIfPossible(path)
|
||||||
info, err = os.Lstat(path)
|
return fi, err
|
||||||
} else {
|
|
||||||
info, err = fs.Stat(path)
|
|
||||||
}
|
}
|
||||||
return
|
return fs.Stat(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk walks the file tree rooted at root, calling walkFn for each file or
|
// Walk walks the file tree rooted at root, calling walkFn for each file or
|
||||||
|
@ -100,7 +98,7 @@ func (a Afero) Walk(root string, walkFn filepath.WalkFunc) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Walk(fs Fs, root string, walkFn filepath.WalkFunc) error {
|
func Walk(fs Fs, root string, walkFn filepath.WalkFunc) error {
|
||||||
info, err := lstatIfOs(fs, root)
|
info, err := lstatIfPossible(fs, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return walkFn(root, nil, err)
|
return walkFn(root, nil, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ Lstater = (*ReadOnlyFs)(nil)
|
||||||
|
|
||||||
type ReadOnlyFs struct {
|
type ReadOnlyFs struct {
|
||||||
source Fs
|
source Fs
|
||||||
}
|
}
|
||||||
|
@ -34,6 +36,14 @@ func (r *ReadOnlyFs) Stat(name string) (os.FileInfo, error) {
|
||||||
return r.source.Stat(name)
|
return r.source.Stat(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ReadOnlyFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
||||||
|
if lsf, ok := r.source.(Lstater); ok {
|
||||||
|
return lsf.LstatIfPossible(name)
|
||||||
|
}
|
||||||
|
fi, err := r.Stat(name)
|
||||||
|
return fi, false, err
|
||||||
|
}
|
||||||
|
|
||||||
func (r *ReadOnlyFs) Rename(o, n string) error {
|
func (r *ReadOnlyFs) Rename(o, n string) error {
|
||||||
return syscall.EPERM
|
return syscall.EPERM
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,9 @@ import (
|
||||||
// successful read in the overlay will move the cursor position in the base layer
|
// successful read in the overlay will move the cursor position in the base layer
|
||||||
// by the number of bytes read.
|
// by the number of bytes read.
|
||||||
type UnionFile struct {
|
type UnionFile struct {
|
||||||
base File
|
Base File
|
||||||
layer File
|
Layer File
|
||||||
|
Merger DirsMerger
|
||||||
off int
|
off int
|
||||||
files []os.FileInfo
|
files []os.FileInfo
|
||||||
}
|
}
|
||||||
|
@ -31,22 +32,22 @@ func (f *UnionFile) Close() error {
|
||||||
// first close base, so we have a newer timestamp in the overlay. If we'd close
|
// first close base, so we have a newer timestamp in the overlay. If we'd close
|
||||||
// the overlay first, we'd get a cacheStale the next time we access this file
|
// the overlay first, we'd get a cacheStale the next time we access this file
|
||||||
// -> cache would be useless ;-)
|
// -> cache would be useless ;-)
|
||||||
if f.base != nil {
|
if f.Base != nil {
|
||||||
f.base.Close()
|
f.Base.Close()
|
||||||
}
|
}
|
||||||
if f.layer != nil {
|
if f.Layer != nil {
|
||||||
return f.layer.Close()
|
return f.Layer.Close()
|
||||||
}
|
}
|
||||||
return BADFD
|
return BADFD
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *UnionFile) Read(s []byte) (int, error) {
|
func (f *UnionFile) Read(s []byte) (int, error) {
|
||||||
if f.layer != nil {
|
if f.Layer != nil {
|
||||||
n, err := f.layer.Read(s)
|
n, err := f.Layer.Read(s)
|
||||||
if (err == nil || err == io.EOF) && f.base != nil {
|
if (err == nil || err == io.EOF) && f.Base != nil {
|
||||||
// advance the file position also in the base file, the next
|
// advance the file position also in the base file, the next
|
||||||
// call may be a write at this position (or a seek with SEEK_CUR)
|
// call may be a write at this position (or a seek with SEEK_CUR)
|
||||||
if _, seekErr := f.base.Seek(int64(n), os.SEEK_CUR); seekErr != nil {
|
if _, seekErr := f.Base.Seek(int64(n), os.SEEK_CUR); seekErr != nil {
|
||||||
// only overwrite err in case the seek fails: we need to
|
// only overwrite err in case the seek fails: we need to
|
||||||
// report an eventual io.EOF to the caller
|
// report an eventual io.EOF to the caller
|
||||||
err = seekErr
|
err = seekErr
|
||||||
|
@ -54,109 +55,150 @@ func (f *UnionFile) Read(s []byte) (int, error) {
|
||||||
}
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
if f.base != nil {
|
if f.Base != nil {
|
||||||
return f.base.Read(s)
|
return f.Base.Read(s)
|
||||||
}
|
}
|
||||||
return 0, BADFD
|
return 0, BADFD
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *UnionFile) ReadAt(s []byte, o int64) (int, error) {
|
func (f *UnionFile) ReadAt(s []byte, o int64) (int, error) {
|
||||||
if f.layer != nil {
|
if f.Layer != nil {
|
||||||
n, err := f.layer.ReadAt(s, o)
|
n, err := f.Layer.ReadAt(s, o)
|
||||||
if (err == nil || err == io.EOF) && f.base != nil {
|
if (err == nil || err == io.EOF) && f.Base != nil {
|
||||||
_, err = f.base.Seek(o+int64(n), os.SEEK_SET)
|
_, err = f.Base.Seek(o+int64(n), os.SEEK_SET)
|
||||||
}
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
if f.base != nil {
|
if f.Base != nil {
|
||||||
return f.base.ReadAt(s, o)
|
return f.Base.ReadAt(s, o)
|
||||||
}
|
}
|
||||||
return 0, BADFD
|
return 0, BADFD
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *UnionFile) Seek(o int64, w int) (pos int64, err error) {
|
func (f *UnionFile) Seek(o int64, w int) (pos int64, err error) {
|
||||||
if f.layer != nil {
|
if f.Layer != nil {
|
||||||
pos, err = f.layer.Seek(o, w)
|
pos, err = f.Layer.Seek(o, w)
|
||||||
if (err == nil || err == io.EOF) && f.base != nil {
|
if (err == nil || err == io.EOF) && f.Base != nil {
|
||||||
_, err = f.base.Seek(o, w)
|
_, err = f.Base.Seek(o, w)
|
||||||
}
|
}
|
||||||
return pos, err
|
return pos, err
|
||||||
}
|
}
|
||||||
if f.base != nil {
|
if f.Base != nil {
|
||||||
return f.base.Seek(o, w)
|
return f.Base.Seek(o, w)
|
||||||
}
|
}
|
||||||
return 0, BADFD
|
return 0, BADFD
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *UnionFile) Write(s []byte) (n int, err error) {
|
func (f *UnionFile) Write(s []byte) (n int, err error) {
|
||||||
if f.layer != nil {
|
if f.Layer != nil {
|
||||||
n, err = f.layer.Write(s)
|
n, err = f.Layer.Write(s)
|
||||||
if err == nil && f.base != nil { // hmm, do we have fixed size files where a write may hit the EOF mark?
|
if err == nil && f.Base != nil { // hmm, do we have fixed size files where a write may hit the EOF mark?
|
||||||
_, err = f.base.Write(s)
|
_, err = f.Base.Write(s)
|
||||||
}
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
if f.base != nil {
|
if f.Base != nil {
|
||||||
return f.base.Write(s)
|
return f.Base.Write(s)
|
||||||
}
|
}
|
||||||
return 0, BADFD
|
return 0, BADFD
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *UnionFile) WriteAt(s []byte, o int64) (n int, err error) {
|
func (f *UnionFile) WriteAt(s []byte, o int64) (n int, err error) {
|
||||||
if f.layer != nil {
|
if f.Layer != nil {
|
||||||
n, err = f.layer.WriteAt(s, o)
|
n, err = f.Layer.WriteAt(s, o)
|
||||||
if err == nil && f.base != nil {
|
if err == nil && f.Base != nil {
|
||||||
_, err = f.base.WriteAt(s, o)
|
_, err = f.Base.WriteAt(s, o)
|
||||||
}
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
if f.base != nil {
|
if f.Base != nil {
|
||||||
return f.base.WriteAt(s, o)
|
return f.Base.WriteAt(s, o)
|
||||||
}
|
}
|
||||||
return 0, BADFD
|
return 0, BADFD
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *UnionFile) Name() string {
|
func (f *UnionFile) Name() string {
|
||||||
if f.layer != nil {
|
if f.Layer != nil {
|
||||||
return f.layer.Name()
|
return f.Layer.Name()
|
||||||
}
|
}
|
||||||
return f.base.Name()
|
return f.Base.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Readdir will weave the two directories together and
|
// DirsMerger is how UnionFile weaves two directories together.
|
||||||
// return a single view of the overlayed directories
|
// It takes the FileInfo slices from the layer and the base and returns a
|
||||||
func (f *UnionFile) Readdir(c int) (ofi []os.FileInfo, err error) {
|
// single view.
|
||||||
if f.off == 0 {
|
type DirsMerger func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error)
|
||||||
|
|
||||||
|
var defaultUnionMergeDirsFn = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) {
|
||||||
var files = make(map[string]os.FileInfo)
|
var files = make(map[string]os.FileInfo)
|
||||||
var rfi []os.FileInfo
|
|
||||||
if f.layer != nil {
|
for _, fi := range lofi {
|
||||||
rfi, err = f.layer.Readdir(-1)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, fi := range rfi {
|
|
||||||
files[fi.Name()] = fi
|
files[fi.Name()] = fi
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if f.base != nil {
|
for _, fi := range bofi {
|
||||||
rfi, err = f.base.Readdir(-1)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, fi := range rfi {
|
|
||||||
if _, exists := files[fi.Name()]; !exists {
|
if _, exists := files[fi.Name()]; !exists {
|
||||||
files[fi.Name()] = fi
|
files[fi.Name()] = fi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
rfi := make([]os.FileInfo, len(files))
|
||||||
|
|
||||||
|
i := 0
|
||||||
for _, fi := range files {
|
for _, fi := range files {
|
||||||
f.files = append(f.files, fi)
|
rfi[i] = fi
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
return rfi, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Readdir will weave the two directories together and
|
||||||
|
// return a single view of the overlayed directories
|
||||||
|
// At the end of the directory view, the error is io.EOF.
|
||||||
|
func (f *UnionFile) Readdir(c int) (ofi []os.FileInfo, err error) {
|
||||||
|
var merge DirsMerger = f.Merger
|
||||||
|
if merge == nil {
|
||||||
|
merge = defaultUnionMergeDirsFn
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.off == 0 {
|
||||||
|
var lfi []os.FileInfo
|
||||||
|
if f.Layer != nil {
|
||||||
|
lfi, err = f.Layer.Readdir(-1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bfi []os.FileInfo
|
||||||
|
if f.Base != nil {
|
||||||
|
bfi, err = f.Base.Readdir(-1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
merged, err := merge(lfi, bfi)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
f.files = append(f.files, merged...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.off >= len(f.files) {
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
if c == -1 {
|
if c == -1 {
|
||||||
return f.files[f.off:], nil
|
return f.files[f.off:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c > len(f.files) {
|
||||||
|
c = len(f.files)
|
||||||
|
}
|
||||||
|
|
||||||
defer func() { f.off += c }()
|
defer func() { f.off += c }()
|
||||||
return f.files[f.off:c], nil
|
return f.files[f.off:c], nil
|
||||||
}
|
}
|
||||||
|
@ -174,53 +216,53 @@ func (f *UnionFile) Readdirnames(c int) ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *UnionFile) Stat() (os.FileInfo, error) {
|
func (f *UnionFile) Stat() (os.FileInfo, error) {
|
||||||
if f.layer != nil {
|
if f.Layer != nil {
|
||||||
return f.layer.Stat()
|
return f.Layer.Stat()
|
||||||
}
|
}
|
||||||
if f.base != nil {
|
if f.Base != nil {
|
||||||
return f.base.Stat()
|
return f.Base.Stat()
|
||||||
}
|
}
|
||||||
return nil, BADFD
|
return nil, BADFD
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *UnionFile) Sync() (err error) {
|
func (f *UnionFile) Sync() (err error) {
|
||||||
if f.layer != nil {
|
if f.Layer != nil {
|
||||||
err = f.layer.Sync()
|
err = f.Layer.Sync()
|
||||||
if err == nil && f.base != nil {
|
if err == nil && f.Base != nil {
|
||||||
err = f.base.Sync()
|
err = f.Base.Sync()
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if f.base != nil {
|
if f.Base != nil {
|
||||||
return f.base.Sync()
|
return f.Base.Sync()
|
||||||
}
|
}
|
||||||
return BADFD
|
return BADFD
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *UnionFile) Truncate(s int64) (err error) {
|
func (f *UnionFile) Truncate(s int64) (err error) {
|
||||||
if f.layer != nil {
|
if f.Layer != nil {
|
||||||
err = f.layer.Truncate(s)
|
err = f.Layer.Truncate(s)
|
||||||
if err == nil && f.base != nil {
|
if err == nil && f.Base != nil {
|
||||||
err = f.base.Truncate(s)
|
err = f.Base.Truncate(s)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if f.base != nil {
|
if f.Base != nil {
|
||||||
return f.base.Truncate(s)
|
return f.Base.Truncate(s)
|
||||||
}
|
}
|
||||||
return BADFD
|
return BADFD
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *UnionFile) WriteString(s string) (n int, err error) {
|
func (f *UnionFile) WriteString(s string) (n int, err error) {
|
||||||
if f.layer != nil {
|
if f.Layer != nil {
|
||||||
n, err = f.layer.WriteString(s)
|
n, err = f.Layer.WriteString(s)
|
||||||
if err == nil && f.base != nil {
|
if err == nil && f.Base != nil {
|
||||||
_, err = f.base.WriteString(s)
|
_, err = f.Base.WriteString(s)
|
||||||
}
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
if f.base != nil {
|
if f.Base != nil {
|
||||||
return f.base.WriteString(s)
|
return f.Base.WriteString(s)
|
||||||
}
|
}
|
||||||
return 0, BADFD
|
return 0, BADFD
|
||||||
}
|
}
|
||||||
|
|
|
@ -413,7 +413,7 @@ github.com/posener/complete/cmd
|
||||||
github.com/posener/complete/match
|
github.com/posener/complete/match
|
||||||
# github.com/satori/go.uuid v0.0.0-20160927100844-b061729afc07
|
# github.com/satori/go.uuid v0.0.0-20160927100844-b061729afc07
|
||||||
github.com/satori/go.uuid
|
github.com/satori/go.uuid
|
||||||
# github.com/spf13/afero v1.0.2
|
# github.com/spf13/afero v1.2.1
|
||||||
github.com/spf13/afero
|
github.com/spf13/afero
|
||||||
github.com/spf13/afero/mem
|
github.com/spf13/afero/mem
|
||||||
# github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d
|
# github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d
|
||||||
|
|
Loading…
Reference in New Issue