mirror of https://github.com/spf13/afero.git
sftpfs: implement Symlinker and RemoveAll
This commit is contained in:
parent
100c9a6d7b
commit
9765fa1da7
|
@ -15,12 +15,15 @@ package sftpfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/sftp"
|
"github.com/pkg/sftp"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ afero.Symlinker = (*Fs)(nil)
|
||||||
|
|
||||||
// Fs is a afero.Fs implementation that uses functions provided by the sftp package.
|
// Fs is a afero.Fs implementation that uses functions provided by the sftp package.
|
||||||
//
|
//
|
||||||
// For details in any method, check the documentation of the sftp package
|
// For details in any method, check the documentation of the sftp package
|
||||||
|
@ -110,9 +113,34 @@ func (s Fs) Remove(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Fs) RemoveAll(path string) error {
|
func (s Fs) RemoveAll(path string) error {
|
||||||
// TODO have a look at os.RemoveAll
|
if path == "" {
|
||||||
// https://github.com/golang/go/blob/master/src/os/path.go#L66
|
return nil
|
||||||
return nil
|
}
|
||||||
|
|
||||||
|
info, _, err := s.LstatIfPossible(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !info.IsDir() {
|
||||||
|
return s.client.Remove(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := s.client.ReadDir(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, file := range files {
|
||||||
|
fp := filepath.Join(path, file.Name())
|
||||||
|
if file.IsDir() {
|
||||||
|
err = s.RemoveAll(fp)
|
||||||
|
} else {
|
||||||
|
err = s.client.Remove(fp)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.client.RemoveDirectory(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Fs) Rename(oldname, newname string) error {
|
func (s Fs) Rename(oldname, newname string) error {
|
||||||
|
@ -138,3 +166,20 @@ func (s Fs) Chown(name string, uid, gid int) error {
|
||||||
func (s Fs) Chtimes(name string, atime time.Time, mtime time.Time) error {
|
func (s Fs) Chtimes(name string, atime time.Time, mtime time.Time) error {
|
||||||
return s.client.Chtimes(name, atime, mtime)
|
return s.client.Chtimes(name, atime, mtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s Fs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
||||||
|
fi, err := s.client.Lstat(name)
|
||||||
|
if err == nil {
|
||||||
|
return fi, true, err
|
||||||
|
}
|
||||||
|
fi, err = s.client.Stat(name)
|
||||||
|
return fi, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Fs) SymlinkIfPossible(oldname, newname string) error {
|
||||||
|
return s.client.Symlink(oldname, newname)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Fs) ReadlinkIfPossible(name string) (string, error) {
|
||||||
|
return s.client.ReadLink(name)
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/sftp"
|
"github.com/pkg/sftp"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -234,9 +235,10 @@ func MakeSSHKeyPair(bits int, pubKeyPath, privateKeyPath string) error {
|
||||||
return ioutil.WriteFile(pubKeyPath, ssh.MarshalAuthorizedKey(pub), 0655)
|
return ioutil.WriteFile(pubKeyPath, ssh.MarshalAuthorizedKey(pub), 0655)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSftpCreate(t *testing.T) {
|
func TestSftp(t *testing.T) {
|
||||||
os.Mkdir("./test", 0777)
|
os.Mkdir("./test", 0777)
|
||||||
MakeSSHKeyPair(1024, "./test/id_rsa.pub", "./test/id_rsa")
|
MakeSSHKeyPair(1024, "./test/id_rsa.pub", "./test/id_rsa")
|
||||||
|
defer os.RemoveAll("./test")
|
||||||
|
|
||||||
go RunSftpServer("./test/")
|
go RunSftpServer("./test/")
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
|
@ -254,16 +256,16 @@ func TestSftpCreate(t *testing.T) {
|
||||||
fs.Chmod("test/foo", os.FileMode(0700))
|
fs.Chmod("test/foo", os.FileMode(0700))
|
||||||
fs.Mkdir("test/bar", os.FileMode(0777))
|
fs.Mkdir("test/bar", os.FileMode(0777))
|
||||||
|
|
||||||
file, err := fs.Create("file1")
|
file, err := fs.Create("./test/file1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
file.Write([]byte("hello "))
|
file.Write([]byte("hello "))
|
||||||
file.WriteString("world!\n")
|
file.WriteString("world!\n")
|
||||||
|
file.Close()
|
||||||
|
|
||||||
f1, err := fs.Open("file1")
|
f1, err := fs.Open("./test/file1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("open: %v", err)
|
log.Fatalf("open: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -274,6 +276,52 @@ func TestSftpCreate(t *testing.T) {
|
||||||
_, _ = f1.Read(b)
|
_, _ = f1.Read(b)
|
||||||
fmt.Println(string(b))
|
fmt.Println(string(b))
|
||||||
|
|
||||||
|
fs.MkdirAll("test/testdir1/testdir2", os.FileMode(0755))
|
||||||
|
linker, ok := fs.(afero.Symlinker)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("not implement symlinker")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = linker.SymlinkIfPossible("./test/file1", "test/testdir1/testdir2/file1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, success, err := linker.LstatIfPossible("test/testdir1/testdir2/file1")
|
||||||
|
if !success {
|
||||||
|
t.Fatal("link stat failed")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
linkPath, err := linker.ReadlinkIfPossible("test/testdir1/testdir2/file1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if linkPath != "./test/file1" {
|
||||||
|
t.Fatal("linkpath error")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fs.RemoveAll("test/testdir1/testdir2/file1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = fs.Stat("test/testdir1/testdir2/file1")
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
t.Fatal("remove all failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fs.RemoveAll("test/testdir1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = fs.Stat("test/testdir1")
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
t.Fatal("remove all failed")
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("done")
|
fmt.Println("done")
|
||||||
// TODO check here if "hello\tworld\n" is in buffer b
|
// TODO check here if "hello\tworld\n" is in buffer b
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue