tested working (for proper implementations)
This commit is contained in:
parent
aee651a375
commit
3e0b2965b4
|
@ -0,0 +1,3 @@
|
||||||
|
*_vfsdata.go
|
||||||
|
.*.sw*
|
||||||
|
.DS_Store
|
|
@ -12,3 +12,10 @@ if err := Copy(vfs, ".", "/tmp/dst/"); nil != err {
|
||||||
fmt.Fprintf(os.Stderr, "couldn't copy vfs: %v\n", err)
|
fmt.Fprintf(os.Stderr, "couldn't copy vfs: %v\n", err)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go generate ./...
|
||||||
|
go test ./...
|
||||||
|
```
|
||||||
|
|
6
copy.go
6
copy.go
|
@ -2,7 +2,6 @@ package vfscopy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
@ -16,7 +15,7 @@ const (
|
||||||
|
|
||||||
// Copy copies src to dest, doesn't matter if src is a directory or a file.
|
// Copy copies src to dest, doesn't matter if src is a directory or a file.
|
||||||
func Copy(vfs FileSystem, src, dest string, opt ...Options) error {
|
func Copy(vfs FileSystem, src, dest string, opt ...Options) error {
|
||||||
//info, err := fs.Lstat(src)
|
// FYI: os.Open does a proper lstat
|
||||||
f, err := vfs.Open(src)
|
f, err := vfs.Open(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -132,10 +131,10 @@ func dcopy(vfs FileSystem, srcdir, destdir string, d File, info os.FileInfo, opt
|
||||||
}
|
}
|
||||||
|
|
||||||
func onsymlink(vfs FileSystem, src, dest string, opt Options) error {
|
func onsymlink(vfs FileSystem, src, dest string, opt Options) error {
|
||||||
fmt.Println("lstat happy")
|
|
||||||
switch opt.OnSymlink(src) {
|
switch opt.OnSymlink(src) {
|
||||||
case Shallow:
|
case Shallow:
|
||||||
return lcopy(vfs, src, dest)
|
return lcopy(vfs, src, dest)
|
||||||
|
/*
|
||||||
case Deep:
|
case Deep:
|
||||||
orig, err := vfs.EvalSymlinks(src)
|
orig, err := vfs.EvalSymlinks(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -151,6 +150,7 @@ func onsymlink(vfs FileSystem, src, dest string, opt Options) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return copy(vfs, orig, dest, f, info, opt)
|
return copy(vfs, orig, dest, f, info, opt)
|
||||||
|
*/
|
||||||
case Skip:
|
case Skip:
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
|
|
81
copy_test.go
81
copy_test.go
|
@ -1,19 +1,90 @@
|
||||||
package vfscopy
|
package vfscopy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"log"
|
||||||
"testing"
|
"testing"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"git.rootprojects.org/root/vfscopy/fixtures"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRecursiveCopy(t *testing.T) {
|
func TestNativeRecursiveCopy(t *testing.T) {
|
||||||
{
|
{
|
||||||
opts := Options{
|
opts := Options{
|
||||||
OnSymlink: func (path string) SymlinkAction {
|
OnSymlink: func(path string) SymlinkAction {
|
||||||
return Shallow
|
return Shallow
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
vfs := Dir("./fixtures/src/")
|
vfs := Dir("./fixtures/fs/")
|
||||||
if err := Copy(vfs, ".", "/tmp/dst/", opts,); nil != err {
|
tmpDir := "/tmp/go-vfscopy-dst-1/"
|
||||||
t.Fatalf("error: %v", err)
|
|
||||||
|
_ = os.RemoveAll(tmpDir)
|
||||||
|
defer func () {
|
||||||
|
_ = os.RemoveAll(tmpDir)
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := Copy(vfs, ".", tmpDir, opts); nil != err {
|
||||||
|
t.Errorf("error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVFSRecursiveCopy(t *testing.T) {
|
||||||
|
{
|
||||||
|
opts := Options{
|
||||||
|
OnSymlink: func(path string) SymlinkAction {
|
||||||
|
return Shallow
|
||||||
|
},
|
||||||
|
}
|
||||||
|
vfs := NewVFS(fixtures.Assets)
|
||||||
|
tmpDir := "/tmp/go-vfscopy-dst-2/"
|
||||||
|
|
||||||
|
_ = os.RemoveAll(tmpDir)
|
||||||
|
defer func () {
|
||||||
|
_ = os.RemoveAll(tmpDir)
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := Copy(vfs, ".", tmpDir, opts); nil != err {
|
||||||
|
t.Errorf("copy error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
root := "fixtures/fs"
|
||||||
|
walker := func(path string, info os.FileInfo, err error) error {
|
||||||
|
if nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rel := path[len(root):]
|
||||||
|
|
||||||
|
s, err := os.Lstat(path)
|
||||||
|
if nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := filepath.Join(tmpDir, rel)
|
||||||
|
d, err := os.Lstat(dst)
|
||||||
|
if nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Mode() != d.Mode() {
|
||||||
|
log.Println("implementation does not support permissions and/or symlinks:", s.Mode(), d.Mode())
|
||||||
|
//return errors.New("did not copy file mode (e.g. symlink status)")
|
||||||
|
} else if s.Size() != d.Size() {
|
||||||
|
return errors.New("did not copy full file size")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(path, "=>", dst)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := filepath.Walk(root, walker)
|
||||||
|
if nil != err {
|
||||||
|
t.Errorf("check dst error: %v", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
// +build !dev
|
||||||
|
|
||||||
|
//go:generate go run -mod vendor github.com/shurcooL/vfsgen/cmd/vfsgendev -source="git.rootprojects.org/root/vfscopy/fixtures".Assets
|
||||||
|
|
||||||
|
package fixtures
|
|
@ -0,0 +1,8 @@
|
||||||
|
// +build dev
|
||||||
|
|
||||||
|
package fixtures
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// Assets is the public file system which should be served by http
|
||||||
|
var Assets http.FileSystem = http.Dir("./fs")
|
6
go.mod
6
go.mod
|
@ -1,3 +1,9 @@
|
||||||
module git.rootprojects.org/root/vfscopy
|
module git.rootprojects.org/root/vfscopy
|
||||||
|
|
||||||
go 1.15
|
go 1.15
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
|
||||||
|
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546
|
||||||
|
golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6 // indirect
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk=
|
||||||
|
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||||
|
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU=
|
||||||
|
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6 h1:rbvTkL9AkFts1cgI78+gG6Yu1pwaqX6hjSJAatB78E4=
|
||||||
|
golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
@ -0,0 +1,10 @@
|
||||||
|
// +build tools
|
||||||
|
|
||||||
|
// Package tools is a faux package for tracking dependencies that don't make it into the code
|
||||||
|
package tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
// these are 'go generate' tooling dependencies, not including in the binary
|
||||||
|
_ "github.com/shurcooL/vfsgen"
|
||||||
|
_ "github.com/shurcooL/vfsgen/cmd/vfsgendev"
|
||||||
|
)
|
|
@ -22,10 +22,8 @@ type Options struct {
|
||||||
type SymlinkAction int
|
type SymlinkAction int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Deep creates hard-copy of contents.
|
|
||||||
Deep SymlinkAction = iota
|
|
||||||
// Shallow creates new symlink to the dest of symlink.
|
// Shallow creates new symlink to the dest of symlink.
|
||||||
Shallow
|
Shallow SymlinkAction = iota
|
||||||
// Skip does nothing with symlink.
|
// Skip does nothing with symlink.
|
||||||
Skip
|
Skip
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
|
||||||
|
## explicit
|
||||||
|
github.com/shurcooL/httpfs/vfsutil
|
||||||
|
# github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546
|
||||||
|
## explicit
|
||||||
|
github.com/shurcooL/vfsgen
|
||||||
|
github.com/shurcooL/vfsgen/cmd/vfsgendev
|
||||||
|
# golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6
|
||||||
|
## explicit
|
37
vfs.go
37
vfs.go
|
@ -3,22 +3,19 @@ package vfscopy
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"errors"
|
"errors"
|
||||||
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTTPFileSystem is copied from http.FileSystem
|
|
||||||
type HTTPFileSystem interface {
|
|
||||||
Open(name string) (File, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileSystem is a Virtual FileSystem with Symlink support
|
// FileSystem is a Virtual FileSystem with Symlink support
|
||||||
type FileSystem interface {
|
type FileSystem interface {
|
||||||
Open(name string) (File, error)
|
Open(name string) (File, error)
|
||||||
Readlink(name string) (string, error)
|
Readlink(name string) (string, error)
|
||||||
EvalSymlinks(name string) (string, error)
|
//EvalSymlinks(name string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// File is copied from http.File
|
// File is copied from http.File
|
||||||
|
@ -30,30 +27,32 @@ type File interface {
|
||||||
Stat() (os.FileInfo, error)
|
Stat() (os.FileInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VFS is a virtual FileSystem with possible Symlink support
|
// VFS is a virtual FileSystem with Symlink support
|
||||||
type VFS struct {
|
type VFS struct {
|
||||||
FileSystem HTTPFileSystem
|
FileSystem http.FileSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open opens a file relative to a virtual filesystem
|
// Open opens a file relative to a virtual filesystem
|
||||||
func (v *VFS) Open(name string) (File, error) {
|
func (v *VFS) Open(name string) (File, error) {
|
||||||
return v.Open(name)
|
return v.FileSystem.Open(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Readlink returns a "not implemented" error,
|
// Readlink returns a "not implemented" error,
|
||||||
// which is okay because it is never called for http.FileSystem.
|
// which is okay because it is never called for http.FileSystem.
|
||||||
func (v *VFS) Readlink(name string) (string, error) {
|
func (v *VFS) Readlink(name string) (string, error) {
|
||||||
return "", errors.New("not implemented")
|
f, err := v.FileSystem.Open(name)
|
||||||
|
if nil != err {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
b, err := ioutil.ReadAll(f)
|
||||||
|
if nil != err {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EvalSymlinks returns the original name,
|
// NewVFS gives an http.FileSystem (real) symlink support
|
||||||
// which is okay because it is never called for http.FileSystem.
|
func NewVFS(httpfs http.FileSystem) FileSystem {
|
||||||
func (v *VFS) EvalSymlinks(name string) (string, error) {
|
|
||||||
return name, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVFS gives an http.FileSystem faux symlink support
|
|
||||||
func NewVFS(httpfs HTTPFileSystem) FileSystem {
|
|
||||||
return &VFS{ FileSystem: httpfs }
|
return &VFS{ FileSystem: httpfs }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +121,7 @@ func (d Dir) Readlink(name string) (string, error) {
|
||||||
return name, nil
|
return name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// EvalSymlinks returns the destination of the named symbolic link.
|
// EvalSymlinks returns the destination of the named symbolic link.
|
||||||
func (d Dir) EvalSymlinks(name string) (string, error) {
|
func (d Dir) EvalSymlinks(name string) (string, error) {
|
||||||
name, err := d.fullName(name)
|
name, err := d.fullName(name)
|
||||||
|
@ -134,3 +134,4 @@ func (d Dir) EvalSymlinks(name string) (string, error) {
|
||||||
}
|
}
|
||||||
return name, nil
|
return name, nil
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
Loading…
Reference in New Issue