Update go dependencies

This commit is contained in:
Manuel de Brito Fontes 2018-05-26 11:27:53 -04:00 committed by Manuel Alejandro de Brito Fontes
parent 15ffb51394
commit bb4d483837
No known key found for this signature in database
GPG key ID: 786136016A8BA02A
1621 changed files with 86368 additions and 284392 deletions

View file

@ -2,8 +2,8 @@ sudo: false
language: go
go:
- 1.7.5
- 1.8
- 1.9
- "1.10"
- tip
os:

View file

@ -1,699 +0,0 @@
// Copyright © 2014 Steve Francia <spf@spf13.com>.
// Copyright 2009 The Go Authors. All rights reserved.
//
// 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 (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"syscall"
"testing"
)
var testName = "test.txt"
var Fss = []Fs{&MemMapFs{}, &OsFs{}}
var testRegistry map[Fs][]string = make(map[Fs][]string)
func testDir(fs Fs) string {
name, err := TempDir(fs, "", "afero")
if err != nil {
panic(fmt.Sprint("unable to work with test dir", err))
}
testRegistry[fs] = append(testRegistry[fs], name)
return name
}
func tmpFile(fs Fs) File {
x, err := TempFile(fs, "", "afero")
if err != nil {
panic(fmt.Sprint("unable to work with temp file", err))
}
testRegistry[fs] = append(testRegistry[fs], x.Name())
return x
}
//Read with length 0 should not return EOF.
func TestRead0(t *testing.T) {
for _, fs := range Fss {
f := tmpFile(fs)
defer f.Close()
f.WriteString("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
var b []byte
// b := make([]byte, 0)
n, err := f.Read(b)
if n != 0 || err != nil {
t.Errorf("%v: Read(0) = %d, %v, want 0, nil", fs.Name(), n, err)
}
f.Seek(0, 0)
b = make([]byte, 100)
n, err = f.Read(b)
if n <= 0 || err != nil {
t.Errorf("%v: Read(100) = %d, %v, want >0, nil", fs.Name(), n, err)
}
}
}
func TestOpenFile(t *testing.T) {
defer removeAllTestFiles(t)
for _, fs := range Fss {
tmp := testDir(fs)
path := filepath.Join(tmp, testName)
f, err := fs.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
if err != nil {
t.Error(fs.Name(), "OpenFile (O_CREATE) failed:", err)
continue
}
io.WriteString(f, "initial")
f.Close()
f, err = fs.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
t.Error(fs.Name(), "OpenFile (O_APPEND) failed:", err)
continue
}
io.WriteString(f, "|append")
f.Close()
f, err = fs.OpenFile(path, os.O_RDONLY, 0600)
contents, _ := ioutil.ReadAll(f)
expectedContents := "initial|append"
if string(contents) != expectedContents {
t.Errorf("%v: appending, expected '%v', got: '%v'", fs.Name(), expectedContents, string(contents))
}
f.Close()
f, err = fs.OpenFile(path, os.O_RDWR|os.O_TRUNC, 0600)
if err != nil {
t.Error(fs.Name(), "OpenFile (O_TRUNC) failed:", err)
continue
}
contents, _ = ioutil.ReadAll(f)
if string(contents) != "" {
t.Errorf("%v: expected truncated file, got: '%v'", fs.Name(), string(contents))
}
f.Close()
}
}
func TestCreate(t *testing.T) {
defer removeAllTestFiles(t)
for _, fs := range Fss {
tmp := testDir(fs)
path := filepath.Join(tmp, testName)
f, err := fs.Create(path)
if err != nil {
t.Error(fs.Name(), "Create failed:", err)
f.Close()
continue
}
io.WriteString(f, "initial")
f.Close()
f, err = fs.Create(path)
if err != nil {
t.Error(fs.Name(), "Create failed:", err)
f.Close()
continue
}
secondContent := "second create"
io.WriteString(f, secondContent)
f.Close()
f, err = fs.Open(path)
if err != nil {
t.Error(fs.Name(), "Open failed:", err)
f.Close()
continue
}
buf, err := ReadAll(f)
if err != nil {
t.Error(fs.Name(), "ReadAll failed:", err)
f.Close()
continue
}
if string(buf) != secondContent {
t.Error(fs.Name(), "Content should be", "\""+secondContent+"\" but is \""+string(buf)+"\"")
f.Close()
continue
}
f.Close()
}
}
func TestMemFileRead(t *testing.T) {
f := tmpFile(new(MemMapFs))
// f := MemFileCreate("testfile")
f.WriteString("abcd")
f.Seek(0, 0)
b := make([]byte, 8)
n, err := f.Read(b)
if n != 4 {
t.Errorf("didn't read all bytes: %v %v %v", n, err, b)
}
if err != nil {
t.Errorf("err is not nil: %v %v %v", n, err, b)
}
n, err = f.Read(b)
if n != 0 {
t.Errorf("read more bytes: %v %v %v", n, err, b)
}
if err != io.EOF {
t.Errorf("error is not EOF: %v %v %v", n, err, b)
}
}
func TestRename(t *testing.T) {
defer removeAllTestFiles(t)
for _, fs := range Fss {
tDir := testDir(fs)
from := filepath.Join(tDir, "/renamefrom")
to := filepath.Join(tDir, "/renameto")
exists := filepath.Join(tDir, "/renameexists")
file, err := fs.Create(from)
if err != nil {
t.Fatalf("%s: open %q failed: %v", fs.Name(), to, err)
}
if err = file.Close(); err != nil {
t.Errorf("%s: close %q failed: %v", fs.Name(), to, err)
}
file, err = fs.Create(exists)
if err != nil {
t.Fatalf("%s: open %q failed: %v", fs.Name(), to, err)
}
if err = file.Close(); err != nil {
t.Errorf("%s: close %q failed: %v", fs.Name(), to, err)
}
err = fs.Rename(from, to)
if err != nil {
t.Fatalf("%s: rename %q, %q failed: %v", fs.Name(), to, from, err)
}
file, err = fs.Create(from)
if err != nil {
t.Fatalf("%s: open %q failed: %v", fs.Name(), to, err)
}
if err = file.Close(); err != nil {
t.Errorf("%s: close %q failed: %v", fs.Name(), to, err)
}
err = fs.Rename(from, exists)
if err != nil {
t.Errorf("%s: rename %q, %q failed: %v", fs.Name(), exists, from, err)
}
names, err := readDirNames(fs, tDir)
if err != nil {
t.Errorf("%s: readDirNames error: %v", fs.Name(), err)
}
found := false
for _, e := range names {
if e == "renamefrom" {
t.Error("File is still called renamefrom")
}
if e == "renameto" {
found = true
}
}
if !found {
t.Error("File was not renamed to renameto")
}
_, err = fs.Stat(to)
if err != nil {
t.Errorf("%s: stat %q failed: %v", fs.Name(), to, err)
}
}
}
func TestRemove(t *testing.T) {
for _, fs := range Fss {
x, err := TempFile(fs, "", "afero")
if err != nil {
t.Error(fmt.Sprint("unable to work with temp file", err))
}
path := x.Name()
x.Close()
tDir := filepath.Dir(path)
err = fs.Remove(path)
if err != nil {
t.Errorf("%v: Remove() failed: %v", fs.Name(), err)
continue
}
_, err = fs.Stat(path)
if !os.IsNotExist(err) {
t.Errorf("%v: Remove() didn't remove file", fs.Name())
continue
}
// Deleting non-existent file should raise error
err = fs.Remove(path)
if !os.IsNotExist(err) {
t.Errorf("%v: Remove() didn't raise error for non-existent file", fs.Name())
}
f, err := fs.Open(tDir)
if err != nil {
t.Error("TestDir should still exist:", err)
}
names, err := f.Readdirnames(-1)
if err != nil {
t.Error("Readdirnames failed:", err)
}
for _, e := range names {
if e == testName {
t.Error("File was not removed from parent directory")
}
}
}
}
func TestTruncate(t *testing.T) {
defer removeAllTestFiles(t)
for _, fs := range Fss {
f := tmpFile(fs)
defer f.Close()
checkSize(t, f, 0)
f.Write([]byte("hello, world\n"))
checkSize(t, f, 13)
f.Truncate(10)
checkSize(t, f, 10)
f.Truncate(1024)
checkSize(t, f, 1024)
f.Truncate(0)
checkSize(t, f, 0)
_, err := f.Write([]byte("surprise!"))
if err == nil {
checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
}
}
}
func TestSeek(t *testing.T) {
defer removeAllTestFiles(t)
for _, fs := range Fss {
f := tmpFile(fs)
defer f.Close()
const data = "hello, world\n"
io.WriteString(f, data)
type test struct {
in int64
whence int
out int64
}
var tests = []test{
{0, 1, int64(len(data))},
{0, 0, 0},
{5, 0, 5},
{0, 2, int64(len(data))},
{0, 0, 0},
{-1, 2, int64(len(data)) - 1},
{1 << 33, 0, 1 << 33},
{1 << 33, 2, 1<<33 + int64(len(data))},
}
for i, tt := range tests {
off, err := f.Seek(tt.in, tt.whence)
if off != tt.out || err != nil {
if e, ok := err.(*os.PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 {
// Reiserfs rejects the big seeks.
// http://code.google.com/p/go/issues/detail?id=91
break
}
t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
}
}
}
}
func TestReadAt(t *testing.T) {
defer removeAllTestFiles(t)
for _, fs := range Fss {
f := tmpFile(fs)
defer f.Close()
const data = "hello, world\n"
io.WriteString(f, data)
b := make([]byte, 5)
n, err := f.ReadAt(b, 7)
if err != nil || n != len(b) {
t.Fatalf("ReadAt 7: %d, %v", n, err)
}
if string(b) != "world" {
t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
}
}
}
func TestWriteAt(t *testing.T) {
defer removeAllTestFiles(t)
for _, fs := range Fss {
f := tmpFile(fs)
defer f.Close()
const data = "hello, world\n"
io.WriteString(f, data)
n, err := f.WriteAt([]byte("WORLD"), 7)
if err != nil || n != 5 {
t.Fatalf("WriteAt 7: %d, %v", n, err)
}
f2, err := fs.Open(f.Name())
if err != nil {
t.Fatalf("%v: ReadFile %s: %v", fs.Name(), f.Name(), err)
}
defer f2.Close()
buf := new(bytes.Buffer)
buf.ReadFrom(f2)
b := buf.Bytes()
if string(b) != "hello, WORLD\n" {
t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
}
}
}
func setupTestDir(t *testing.T, fs Fs) string {
path := testDir(fs)
return setupTestFiles(t, fs, path)
}
func setupTestDirRoot(t *testing.T, fs Fs) string {
path := testDir(fs)
setupTestFiles(t, fs, path)
return path
}
func setupTestDirReusePath(t *testing.T, fs Fs, path string) string {
testRegistry[fs] = append(testRegistry[fs], path)
return setupTestFiles(t, fs, path)
}
func setupTestFiles(t *testing.T, fs Fs, path string) string {
testSubDir := filepath.Join(path, "more", "subdirectories", "for", "testing", "we")
err := fs.MkdirAll(testSubDir, 0700)
if err != nil && !os.IsExist(err) {
t.Fatal(err)
}
f, err := fs.Create(filepath.Join(testSubDir, "testfile1"))
if err != nil {
t.Fatal(err)
}
f.WriteString("Testfile 1 content")
f.Close()
f, err = fs.Create(filepath.Join(testSubDir, "testfile2"))
if err != nil {
t.Fatal(err)
}
f.WriteString("Testfile 2 content")
f.Close()
f, err = fs.Create(filepath.Join(testSubDir, "testfile3"))
if err != nil {
t.Fatal(err)
}
f.WriteString("Testfile 3 content")
f.Close()
f, err = fs.Create(filepath.Join(testSubDir, "testfile4"))
if err != nil {
t.Fatal(err)
}
f.WriteString("Testfile 4 content")
f.Close()
return testSubDir
}
func TestReaddirnames(t *testing.T) {
defer removeAllTestFiles(t)
for _, fs := range Fss {
testSubDir := setupTestDir(t, fs)
tDir := filepath.Dir(testSubDir)
root, err := fs.Open(tDir)
if err != nil {
t.Fatal(fs.Name(), tDir, err)
}
defer root.Close()
namesRoot, err := root.Readdirnames(-1)
if err != nil {
t.Fatal(fs.Name(), namesRoot, err)
}
sub, err := fs.Open(testSubDir)
if err != nil {
t.Fatal(err)
}
defer sub.Close()
namesSub, err := sub.Readdirnames(-1)
if err != nil {
t.Fatal(fs.Name(), namesSub, err)
}
findNames(fs, t, tDir, testSubDir, namesRoot, namesSub)
}
}
func TestReaddirSimple(t *testing.T) {
defer removeAllTestFiles(t)
for _, fs := range Fss {
testSubDir := setupTestDir(t, fs)
tDir := filepath.Dir(testSubDir)
root, err := fs.Open(tDir)
if err != nil {
t.Fatal(err)
}
defer root.Close()
rootInfo, err := root.Readdir(1)
if err != nil {
t.Log(myFileInfo(rootInfo))
t.Error(err)
}
rootInfo, err = root.Readdir(5)
if err != io.EOF {
t.Log(myFileInfo(rootInfo))
t.Error(err)
}
sub, err := fs.Open(testSubDir)
if err != nil {
t.Fatal(err)
}
defer sub.Close()
subInfo, err := sub.Readdir(5)
if err != nil {
t.Log(myFileInfo(subInfo))
t.Error(err)
}
}
}
func TestReaddir(t *testing.T) {
defer removeAllTestFiles(t)
for num := 0; num < 6; num++ {
outputs := make([]string, len(Fss))
infos := make([]string, len(Fss))
for i, fs := range Fss {
testSubDir := setupTestDir(t, fs)
//tDir := filepath.Dir(testSubDir)
root, err := fs.Open(testSubDir)
if err != nil {
t.Fatal(err)
}
defer root.Close()
for j := 0; j < 6; j++ {
info, err := root.Readdir(num)
outputs[i] += fmt.Sprintf("%v Error: %v\n", myFileInfo(info), err)
infos[i] += fmt.Sprintln(len(info), err)
}
}
fail := false
for i, o := range infos {
if i == 0 {
continue
}
if o != infos[i-1] {
fail = true
break
}
}
if fail {
t.Log("Readdir outputs not equal for Readdir(", num, ")")
for i, o := range outputs {
t.Log(Fss[i].Name())
t.Log(o)
}
t.Fail()
}
}
}
type myFileInfo []os.FileInfo
func (m myFileInfo) String() string {
out := "Fileinfos:\n"
for _, e := range m {
out += " " + e.Name() + "\n"
}
return out
}
func TestReaddirAll(t *testing.T) {
defer removeAllTestFiles(t)
for _, fs := range Fss {
testSubDir := setupTestDir(t, fs)
tDir := filepath.Dir(testSubDir)
root, err := fs.Open(tDir)
if err != nil {
t.Fatal(err)
}
defer root.Close()
rootInfo, err := root.Readdir(-1)
if err != nil {
t.Fatal(err)
}
var namesRoot = []string{}
for _, e := range rootInfo {
namesRoot = append(namesRoot, e.Name())
}
sub, err := fs.Open(testSubDir)
if err != nil {
t.Fatal(err)
}
defer sub.Close()
subInfo, err := sub.Readdir(-1)
if err != nil {
t.Fatal(err)
}
var namesSub = []string{}
for _, e := range subInfo {
namesSub = append(namesSub, e.Name())
}
findNames(fs, t, tDir, testSubDir, namesRoot, namesSub)
}
}
func findNames(fs Fs, t *testing.T, tDir, testSubDir string, root, sub []string) {
var foundRoot bool
for _, e := range root {
f, err := fs.Open(filepath.Join(tDir, e))
if err != nil {
t.Error("Open", filepath.Join(tDir, e), ":", err)
}
defer f.Close()
if equal(e, "we") {
foundRoot = true
}
}
if !foundRoot {
t.Logf("Names root: %v", root)
t.Logf("Names sub: %v", sub)
t.Error("Didn't find subdirectory we")
}
var found1, found2 bool
for _, e := range sub {
f, err := fs.Open(filepath.Join(testSubDir, e))
if err != nil {
t.Error("Open", filepath.Join(testSubDir, e), ":", err)
}
defer f.Close()
if equal(e, "testfile1") {
found1 = true
}
if equal(e, "testfile2") {
found2 = true
}
}
if !found1 {
t.Logf("Names root: %v", root)
t.Logf("Names sub: %v", sub)
t.Error("Didn't find testfile1")
}
if !found2 {
t.Logf("Names root: %v", root)
t.Logf("Names sub: %v", sub)
t.Error("Didn't find testfile2")
}
}
func removeAllTestFiles(t *testing.T) {
for fs, list := range testRegistry {
for _, path := range list {
if err := fs.RemoveAll(path); err != nil {
t.Error(fs.Name(), err)
}
}
}
testRegistry = make(map[Fs][]string)
}
func equal(name1, name2 string) (r bool) {
switch runtime.GOOS {
case "windows":
r = strings.ToLower(name1) == strings.ToLower(name2)
default:
r = name1 == name2
}
return
}
func checkSize(t *testing.T, f File, size int64) {
dir, err := f.Stat()
if err != nil {
t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
}
if dir.Size() != size {
t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size)
}
}

View file

@ -1,7 +1,6 @@
package afero
import (
"errors"
"os"
"path/filepath"
"runtime"
@ -9,6 +8,8 @@ import (
"time"
)
var _ Lstater = (*BasePathFs)(nil)
// 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 base path before calling the base Fs.
@ -22,6 +23,16 @@ type BasePathFs struct {
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 {
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
func (b *BasePathFs) RealPath(name string) (path string, err error) {
if err := validateBasePathName(name); err != nil {
return "", err
return name, err
}
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
// We could strip out the base part, but that would not be very portable.
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
@ -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 {
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) {
if name, err = b.RealPath(name); err != nil {
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) {
@ -139,7 +158,23 @@ func (b *BasePathFs) Create(name string) (f File, err error) {
if name, err = b.RealPath(name); err != nil {
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

View file

@ -1,142 +0,0 @@
package afero
import (
"os"
"path/filepath"
"runtime"
"testing"
)
func TestBasePath(t *testing.T) {
baseFs := &MemMapFs{}
baseFs.MkdirAll("/base/path/tmp", 0777)
bp := NewBasePathFs(baseFs, "/base/path")
if _, err := bp.Create("/tmp/foo"); err != nil {
t.Errorf("Failed to set real path")
}
if fh, err := bp.Create("../tmp/bar"); err == nil {
t.Errorf("succeeded in creating %s ...", fh.Name())
}
}
func TestBasePathRoot(t *testing.T) {
baseFs := &MemMapFs{}
baseFs.MkdirAll("/base/path/foo/baz", 0777)
baseFs.MkdirAll("/base/path/boo/", 0777)
bp := NewBasePathFs(baseFs, "/base/path")
rd, err := ReadDir(bp, string(os.PathSeparator))
if len(rd) != 2 {
t.Errorf("base path doesn't respect root")
}
if err != nil {
t.Error(err)
}
}
func TestRealPath(t *testing.T) {
fs := NewOsFs()
baseDir, err := TempDir(fs, "", "base")
if err != nil {
t.Fatal("error creating tempDir", err)
}
defer fs.RemoveAll(baseDir)
anotherDir, err := TempDir(fs, "", "another")
if err != nil {
t.Fatal("error creating tempDir", err)
}
defer fs.RemoveAll(anotherDir)
bp := NewBasePathFs(fs, baseDir).(*BasePathFs)
subDir := filepath.Join(baseDir, "s1")
realPath, err := bp.RealPath("/s1")
if err != nil {
t.Errorf("Got error %s", err)
}
if realPath != subDir {
t.Errorf("Expected \n%s got \n%s", subDir, realPath)
}
if runtime.GOOS == "windows" {
_, err = bp.RealPath(anotherDir)
if err == nil {
t.Errorf("Expected error")
}
} else {
// on *nix we have no way of just looking at the path and tell that anotherDir
// is not inside the base file system.
// The user will receive an os.ErrNotExist later.
surrealPath, err := bp.RealPath(anotherDir)
if err != nil {
t.Errorf("Got error %s", err)
}
excpected := filepath.Join(baseDir, anotherDir)
if surrealPath != excpected {
t.Errorf("Expected \n%s got \n%s", excpected, surrealPath)
}
}
}
func TestNestedBasePaths(t *testing.T) {
type dirSpec struct {
Dir1, Dir2, Dir3 string
}
dirSpecs := []dirSpec{
dirSpec{Dir1: "/", Dir2: "/", Dir3: "/"},
dirSpec{Dir1: "/", Dir2: "/path2", Dir3: "/"},
dirSpec{Dir1: "/path1/dir", Dir2: "/path2/dir/", Dir3: "/path3/dir"},
dirSpec{Dir1: "C:/path1", Dir2: "path2/dir", Dir3: "/path3/dir/"},
}
for _, ds := range dirSpecs {
memFs := NewMemMapFs()
level1Fs := NewBasePathFs(memFs, ds.Dir1)
level2Fs := NewBasePathFs(level1Fs, ds.Dir2)
level3Fs := NewBasePathFs(level2Fs, ds.Dir3)
type spec struct {
BaseFs Fs
FileName string
}
specs := []spec{
spec{BaseFs: level3Fs, FileName: "f.txt"},
spec{BaseFs: level2Fs, FileName: "f.txt"},
spec{BaseFs: level1Fs, FileName: "f.txt"},
}
for _, s := range specs {
if err := s.BaseFs.MkdirAll(s.FileName, 0755); err != nil {
t.Errorf("Got error %s", err.Error())
}
if _, err := s.BaseFs.Stat(s.FileName); err != nil {
t.Errorf("Got error %s", err.Error())
}
if s.BaseFs == level3Fs {
pathToExist := filepath.Join(ds.Dir3, s.FileName)
if _, err := level2Fs.Stat(pathToExist); err != nil {
t.Errorf("Got error %s (path %s)", err.Error(), pathToExist)
}
} else if s.BaseFs == level2Fs {
pathToExist := filepath.Join(ds.Dir2, ds.Dir3, s.FileName)
if _, err := level1Fs.Stat(pathToExist); err != nil {
t.Errorf("Got error %s (path %s)", err.Error(), pathToExist)
}
}
}
}
}

View file

@ -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...?
return nil, err
}
return &UnionFile{base: bfi, layer: lfi}, nil
return &UnionFile{Base: bfi, Layer: lfi}, nil
}
return u.layer.OpenFile(name, flag, perm)
}
@ -251,7 +251,7 @@ func (u *CacheOnReadFs) Open(name string) (File, error) {
if err != nil && bfile == nil {
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 {
@ -286,5 +286,5 @@ func (u *CacheOnReadFs) Create(name string) (File, error) {
bfh.Close()
return nil, err
}
return &UnionFile{base: bfh, layer: lfh}, nil
return &UnionFile{Base: bfh, Layer: lfh}, nil
}

View file

@ -1,404 +0,0 @@
package afero
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"testing"
"time"
)
var tempDirs []string
func NewTempOsBaseFs(t *testing.T) Fs {
name, err := TempDir(NewOsFs(), "", "")
if err != nil {
t.Error("error creating tempDir", err)
}
tempDirs = append(tempDirs, name)
return NewBasePathFs(NewOsFs(), name)
}
func CleanupTempDirs(t *testing.T) {
osfs := NewOsFs()
type ev struct {
path string
e error
}
errs := []ev{}
for _, x := range tempDirs {
err := osfs.RemoveAll(x)
if err != nil {
errs = append(errs, ev{path: x, e: err})
}
}
for _, e := range errs {
fmt.Println("error removing tempDir", e.path, e.e)
}
if len(errs) > 0 {
t.Error("error cleaning up tempDirs")
}
tempDirs = []string{}
}
func TestUnionCreateExisting(t *testing.T) {
base := &MemMapFs{}
roBase := &ReadOnlyFs{source: base}
ufs := NewCopyOnWriteFs(roBase, &MemMapFs{})
base.MkdirAll("/home/test", 0777)
fh, _ := base.Create("/home/test/file.txt")
fh.WriteString("This is a test")
fh.Close()
fh, err := ufs.OpenFile("/home/test/file.txt", os.O_RDWR, 0666)
if err != nil {
t.Errorf("Failed to open file r/w: %s", err)
}
_, err = fh.Write([]byte("####"))
if err != nil {
t.Errorf("Failed to write file: %s", err)
}
fh.Seek(0, 0)
data, err := ioutil.ReadAll(fh)
if err != nil {
t.Errorf("Failed to read file: %s", err)
}
if string(data) != "#### is a test" {
t.Errorf("Got wrong data")
}
fh.Close()
fh, _ = base.Open("/home/test/file.txt")
data, err = ioutil.ReadAll(fh)
if string(data) != "This is a test" {
t.Errorf("Got wrong data in base file")
}
fh.Close()
fh, err = ufs.Create("/home/test/file.txt")
switch err {
case nil:
if fi, _ := fh.Stat(); fi.Size() != 0 {
t.Errorf("Create did not truncate file")
}
fh.Close()
default:
t.Errorf("Create failed on existing file")
}
}
func TestUnionMergeReaddir(t *testing.T) {
base := &MemMapFs{}
roBase := &ReadOnlyFs{source: base}
ufs := &CopyOnWriteFs{base: roBase, layer: &MemMapFs{}}
base.MkdirAll("/home/test", 0777)
fh, _ := base.Create("/home/test/file.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = ufs.Create("/home/test/file2.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = ufs.Open("/home/test")
files, err := fh.Readdirnames(-1)
if err != nil {
t.Errorf("Readdirnames failed")
}
if len(files) != 2 {
t.Errorf("Got wrong number of files: %v", files)
}
}
func TestExistingDirectoryCollisionReaddir(t *testing.T) {
base := &MemMapFs{}
roBase := &ReadOnlyFs{source: base}
overlay := &MemMapFs{}
ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
base.MkdirAll("/home/test", 0777)
fh, _ := base.Create("/home/test/file.txt")
fh.WriteString("This is a test")
fh.Close()
overlay.MkdirAll("home/test", 0777)
fh, _ = overlay.Create("/home/test/file2.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = ufs.Create("/home/test/file3.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = ufs.Open("/home/test")
files, err := fh.Readdirnames(-1)
if err != nil {
t.Errorf("Readdirnames failed")
}
if len(files) != 3 {
t.Errorf("Got wrong number of files in union: %v", files)
}
fh, _ = overlay.Open("/home/test")
files, err = fh.Readdirnames(-1)
if err != nil {
t.Errorf("Readdirnames failed")
}
if len(files) != 2 {
t.Errorf("Got wrong number of files in overlay: %v", files)
}
}
func TestNestedDirBaseReaddir(t *testing.T) {
base := &MemMapFs{}
roBase := &ReadOnlyFs{source: base}
overlay := &MemMapFs{}
ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
base.MkdirAll("/home/test/foo/bar", 0777)
fh, _ := base.Create("/home/test/file.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = base.Create("/home/test/foo/file2.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = base.Create("/home/test/foo/bar/file3.txt")
fh.WriteString("This is a test")
fh.Close()
overlay.MkdirAll("/", 0777)
// Opening something only in the base
fh, _ = ufs.Open("/home/test/foo")
list, err := fh.Readdir(-1)
if err != nil {
t.Errorf("Readdir failed %s", err)
}
if len(list) != 2 {
for _, x := range list {
fmt.Println(x.Name())
}
t.Errorf("Got wrong number of files in union: %v", len(list))
}
}
func TestNestedDirOverlayReaddir(t *testing.T) {
base := &MemMapFs{}
roBase := &ReadOnlyFs{source: base}
overlay := &MemMapFs{}
ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
base.MkdirAll("/", 0777)
overlay.MkdirAll("/home/test/foo/bar", 0777)
fh, _ := overlay.Create("/home/test/file.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = overlay.Create("/home/test/foo/file2.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = overlay.Create("/home/test/foo/bar/file3.txt")
fh.WriteString("This is a test")
fh.Close()
// Opening nested dir only in the overlay
fh, _ = ufs.Open("/home/test/foo")
list, err := fh.Readdir(-1)
if err != nil {
t.Errorf("Readdir failed %s", err)
}
if len(list) != 2 {
for _, x := range list {
fmt.Println(x.Name())
}
t.Errorf("Got wrong number of files in union: %v", len(list))
}
}
func TestNestedDirOverlayOsFsReaddir(t *testing.T) {
defer CleanupTempDirs(t)
base := NewTempOsBaseFs(t)
roBase := &ReadOnlyFs{source: base}
overlay := NewTempOsBaseFs(t)
ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
base.MkdirAll("/", 0777)
overlay.MkdirAll("/home/test/foo/bar", 0777)
fh, _ := overlay.Create("/home/test/file.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = overlay.Create("/home/test/foo/file2.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = overlay.Create("/home/test/foo/bar/file3.txt")
fh.WriteString("This is a test")
fh.Close()
// Opening nested dir only in the overlay
fh, _ = ufs.Open("/home/test/foo")
list, err := fh.Readdir(-1)
fh.Close()
if err != nil {
t.Errorf("Readdir failed %s", err)
}
if len(list) != 2 {
for _, x := range list {
fmt.Println(x.Name())
}
t.Errorf("Got wrong number of files in union: %v", len(list))
}
}
func TestCopyOnWriteFsWithOsFs(t *testing.T) {
defer CleanupTempDirs(t)
base := NewTempOsBaseFs(t)
roBase := &ReadOnlyFs{source: base}
overlay := NewTempOsBaseFs(t)
ufs := &CopyOnWriteFs{base: roBase, layer: overlay}
base.MkdirAll("/home/test", 0777)
fh, _ := base.Create("/home/test/file.txt")
fh.WriteString("This is a test")
fh.Close()
overlay.MkdirAll("home/test", 0777)
fh, _ = overlay.Create("/home/test/file2.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = ufs.Create("/home/test/file3.txt")
fh.WriteString("This is a test")
fh.Close()
fh, _ = ufs.Open("/home/test")
files, err := fh.Readdirnames(-1)
fh.Close()
if err != nil {
t.Errorf("Readdirnames failed")
}
if len(files) != 3 {
t.Errorf("Got wrong number of files in union: %v", files)
}
fh, _ = overlay.Open("/home/test")
files, err = fh.Readdirnames(-1)
fh.Close()
if err != nil {
t.Errorf("Readdirnames failed")
}
if len(files) != 2 {
t.Errorf("Got wrong number of files in overlay: %v", files)
}
}
func TestUnionCacheWrite(t *testing.T) {
base := &MemMapFs{}
layer := &MemMapFs{}
ufs := NewCacheOnReadFs(base, layer, 0)
base.Mkdir("/data", 0777)
fh, err := ufs.Create("/data/file.txt")
if err != nil {
t.Errorf("Failed to create file")
}
_, err = fh.Write([]byte("This is a test"))
if err != nil {
t.Errorf("Failed to write file")
}
fh.Seek(0, os.SEEK_SET)
buf := make([]byte, 4)
_, err = fh.Read(buf)
fh.Write([]byte(" IS A"))
fh.Close()
baseData, _ := ReadFile(base, "/data/file.txt")
layerData, _ := ReadFile(layer, "/data/file.txt")
if string(baseData) != string(layerData) {
t.Errorf("Different data: %s <=> %s", baseData, layerData)
}
}
func TestUnionCacheExpire(t *testing.T) {
base := &MemMapFs{}
layer := &MemMapFs{}
ufs := &CacheOnReadFs{base: base, layer: layer, cacheTime: 1 * time.Second}
base.Mkdir("/data", 0777)
fh, err := ufs.Create("/data/file.txt")
if err != nil {
t.Errorf("Failed to create file")
}
_, err = fh.Write([]byte("This is a test"))
if err != nil {
t.Errorf("Failed to write file")
}
fh.Close()
fh, _ = base.Create("/data/file.txt")
// sleep some time, so we really get a different time.Now() on write...
time.Sleep(2 * time.Second)
fh.WriteString("Another test")
fh.Close()
data, _ := ReadFile(ufs, "/data/file.txt")
if string(data) != "Another test" {
t.Errorf("cache time failed: <%s>", data)
}
}
func TestCacheOnReadFsNotInLayer(t *testing.T) {
base := NewMemMapFs()
layer := NewMemMapFs()
fs := NewCacheOnReadFs(base, layer, 0)
fh, err := base.Create("/file.txt")
if err != nil {
t.Fatal("unable to create file: ", err)
}
txt := []byte("This is a test")
fh.Write(txt)
fh.Close()
fh, err = fs.Open("/file.txt")
if err != nil {
t.Fatal("could not open file: ", err)
}
b, err := ReadAll(fh)
fh.Close()
if err != nil {
t.Fatal("could not read file: ", err)
} else if !bytes.Equal(txt, b) {
t.Fatalf("wanted file text %q, got %q", txt, b)
}
fh, err = layer.Open("/file.txt")
if err != nil {
t.Fatal("could not open file from layer: ", err)
}
fh.Close()
}

View file

@ -8,6 +8,8 @@ import (
"time"
)
var _ Lstater = (*CopyOnWriteFs)(nil)
// 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
// be made in the overlay: Changing an existing file in the base layer which
@ -76,18 +78,55 @@ func (u *CopyOnWriteFs) Chmod(name string, mode os.FileMode) error {
func (u *CopyOnWriteFs) Stat(name string) (os.FileInfo, error) {
fi, err := u.layer.Stat(name)
if err != nil {
origErr := err
if e, ok := err.(*os.PathError); ok {
err = e.Err
}
if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENOTDIR {
isNotExist := u.isNotExist(err)
if isNotExist {
return u.base.Stat(name)
}
return nil, origErr
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 {
err = e.Err
}
if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENOTDIR {
return true
}
return false
}
// Renaming files present only in the base layer is not permitted
func (u *CopyOnWriteFs) Rename(oldname, newname string) error {
b, err := u.isBaseFile(oldname)
@ -219,7 +258,7 @@ func (u *CopyOnWriteFs) Open(name string) (File, error) {
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 {

View file

@ -1,39 +0,0 @@
package afero
import "testing"
func TestCopyOnWrite(t *testing.T) {
var fs Fs
var err error
base := NewOsFs()
roBase := NewReadOnlyFs(base)
ufs := NewCopyOnWriteFs(roBase, NewMemMapFs())
fs = ufs
err = fs.MkdirAll("nonexistent/directory/", 0744)
if err != nil {
t.Error(err)
return
}
_, err = fs.Create("nonexistent/directory/newfile")
if err != nil {
t.Error(err)
return
}
}
func TestCopyOnWriteFileInMemMapBase(t *testing.T) {
base := &MemMapFs{}
layer := &MemMapFs{}
if err := WriteFile(base, "base.txt", []byte("base"), 0755); err != nil {
t.Fatalf("Failed to write file: %s", err)
}
ufs := NewCopyOnWriteFs(base, layer)
_, err := ufs.Stat("base.txt")
if err != nil {
t.Fatal(err)
}
}

View file

@ -1,112 +0,0 @@
// ©2015 The Go Authors
// Copyright ©2015 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 "testing"
func checkSizePath(t *testing.T, path string, size int64) {
dir, err := testFS.Stat(path)
if err != nil {
t.Fatalf("Stat %q (looking for size %d): %s", path, size, err)
}
if dir.Size() != size {
t.Errorf("Stat %q: size %d want %d", path, dir.Size(), size)
}
}
func TestReadFile(t *testing.T) {
testFS = &MemMapFs{}
fsutil := &Afero{Fs: testFS}
testFS.Create("this_exists.go")
filename := "rumpelstilzchen"
contents, err := fsutil.ReadFile(filename)
if err == nil {
t.Fatalf("ReadFile %s: error expected, none found", filename)
}
filename = "this_exists.go"
contents, err = fsutil.ReadFile(filename)
if err != nil {
t.Fatalf("ReadFile %s: %v", filename, err)
}
checkSizePath(t, filename, int64(len(contents)))
}
func TestWriteFile(t *testing.T) {
testFS = &MemMapFs{}
fsutil := &Afero{Fs: testFS}
f, err := fsutil.TempFile("", "ioutil-test")
if err != nil {
t.Fatal(err)
}
filename := f.Name()
data := "Programming today is a race between software engineers striving to " +
"build bigger and better idiot-proof programs, and the Universe trying " +
"to produce bigger and better idiots. So far, the Universe is winning."
if err := fsutil.WriteFile(filename, []byte(data), 0644); err != nil {
t.Fatalf("WriteFile %s: %v", filename, err)
}
contents, err := fsutil.ReadFile(filename)
if err != nil {
t.Fatalf("ReadFile %s: %v", filename, err)
}
if string(contents) != data {
t.Fatalf("contents = %q\nexpected = %q", string(contents), data)
}
// cleanup
f.Close()
testFS.Remove(filename) // ignore error
}
func TestReadDir(t *testing.T) {
testFS = &MemMapFs{}
testFS.Mkdir("/i-am-a-dir", 0777)
testFS.Create("/this_exists.go")
dirname := "rumpelstilzchen"
_, err := ReadDir(testFS, dirname)
if err == nil {
t.Fatalf("ReadDir %s: error expected, none found", dirname)
}
dirname = ".."
list, err := ReadDir(testFS, dirname)
if err != nil {
t.Fatalf("ReadDir %s: %v", dirname, err)
}
foundFile := false
foundSubDir := false
for _, dir := range list {
switch {
case !dir.IsDir() && dir.Name() == "this_exists.go":
foundFile = true
case dir.IsDir() && dir.Name() == "i-am-a-dir":
foundSubDir = true
}
}
if !foundFile {
t.Fatalf("ReadDir %s: this_exists.go file not found", dirname)
}
if !foundSubDir {
t.Fatalf("ReadDir %s: i-am-a-dir directory not found", dirname)
}
}

27
vendor/github.com/spf13/afero/lstater.go generated vendored Normal file
View file

@ -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)
}

View file

@ -33,8 +33,8 @@ import (
// built-ins from that package.
func Glob(fs Fs, pattern string) (matches []string, err error) {
if !hasMeta(pattern) {
// afero does not support Lstat directly.
if _, err = lstatIfOs(fs, pattern); err != nil {
// Lstat not supported by a ll filesystems.
if _, err = lstatIfPossible(fs, pattern); err != nil {
return nil, nil
}
return []string{pattern}, nil

View file

@ -1,183 +0,0 @@
// Copyright © 2014 Steve Francia <spf@spf13.com>.
// Copyright 2009 The Go Authors. All rights reserved.
//
// 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"
"path/filepath"
"runtime"
"testing"
)
// contains returns true if vector contains the string s.
func contains(vector []string, s string) bool {
for _, elem := range vector {
if elem == s {
return true
}
}
return false
}
func setupGlobDirRoot(t *testing.T, fs Fs) string {
path := testDir(fs)
setupGlobFiles(t, fs, path)
return path
}
func setupGlobDirReusePath(t *testing.T, fs Fs, path string) string {
testRegistry[fs] = append(testRegistry[fs], path)
return setupGlobFiles(t, fs, path)
}
func setupGlobFiles(t *testing.T, fs Fs, path string) string {
testSubDir := filepath.Join(path, "globs", "bobs")
err := fs.MkdirAll(testSubDir, 0700)
if err != nil && !os.IsExist(err) {
t.Fatal(err)
}
f, err := fs.Create(filepath.Join(testSubDir, "/matcher"))
if err != nil {
t.Fatal(err)
}
f.WriteString("Testfile 1 content")
f.Close()
f, err = fs.Create(filepath.Join(testSubDir, "/../submatcher"))
if err != nil {
t.Fatal(err)
}
f.WriteString("Testfile 2 content")
f.Close()
f, err = fs.Create(filepath.Join(testSubDir, "/../../match"))
if err != nil {
t.Fatal(err)
}
f.WriteString("Testfile 3 content")
f.Close()
return testSubDir
}
func TestGlob(t *testing.T) {
defer removeAllTestFiles(t)
var testDir string
for i, fs := range Fss {
if i == 0 {
testDir = setupGlobDirRoot(t, fs)
} else {
setupGlobDirReusePath(t, fs, testDir)
}
}
var globTests = []struct {
pattern, result string
}{
{testDir + "/globs/bobs/matcher", testDir + "/globs/bobs/matcher"},
{testDir + "/globs/*/mat?her", testDir + "/globs/bobs/matcher"},
{testDir + "/globs/bobs/../*", testDir + "/globs/submatcher"},
{testDir + "/match", testDir + "/match"},
}
for _, fs := range Fss {
for _, tt := range globTests {
pattern := tt.pattern
result := tt.result
if runtime.GOOS == "windows" {
pattern = filepath.Clean(pattern)
result = filepath.Clean(result)
}
matches, err := Glob(fs, pattern)
if err != nil {
t.Errorf("Glob error for %q: %s", pattern, err)
continue
}
if !contains(matches, result) {
t.Errorf("Glob(%#q) = %#v want %v", pattern, matches, result)
}
}
for _, pattern := range []string{"no_match", "../*/no_match"} {
matches, err := Glob(fs, pattern)
if err != nil {
t.Errorf("Glob error for %q: %s", pattern, err)
continue
}
if len(matches) != 0 {
t.Errorf("Glob(%#q) = %#v want []", pattern, matches)
}
}
}
}
func TestGlobSymlink(t *testing.T) {
defer removeAllTestFiles(t)
fs := &OsFs{}
testDir := setupGlobDirRoot(t, fs)
err := os.Symlink("target", filepath.Join(testDir, "symlink"))
if err != nil {
t.Skipf("skipping on %s", runtime.GOOS)
}
var globSymlinkTests = []struct {
path, dest string
brokenLink bool
}{
{"test1", "link1", false},
{"test2", "link2", true},
}
for _, tt := range globSymlinkTests {
path := filepath.Join(testDir, tt.path)
dest := filepath.Join(testDir, tt.dest)
f, err := fs.Create(path)
if err != nil {
t.Fatal(err)
}
if err := f.Close(); err != nil {
t.Fatal(err)
}
err = os.Symlink(path, dest)
if err != nil {
t.Fatal(err)
}
if tt.brokenLink {
// Break the symlink.
fs.Remove(path)
}
matches, err := Glob(fs, dest)
if err != nil {
t.Errorf("GlobSymlink error for %q: %s", dest, err)
}
if !contains(matches, dest) {
t.Errorf("Glob(%#q) = %#v want %v", dest, matches, dest)
}
}
}
func TestGlobError(t *testing.T) {
for _, fs := range Fss {
_, err := Glob(fs, "[7]")
if err != nil {
t.Error("expected error for bad pattern; got none")
}
}
}

View file

@ -176,6 +176,9 @@ func (f *File) Read(b []byte) (n int, err error) {
if len(b) > 0 && int(f.at) == len(f.fileData.data) {
return 0, io.EOF
}
if int(f.at) > len(f.fileData.data) {
return 0, io.ErrUnexpectedEOF
}
if len(f.fileData.data)-int(f.at) >= len(b) {
n = len(b)
} else {

View file

@ -1,154 +0,0 @@
package mem
import (
"testing"
"time"
)
func TestFileDataNameRace(t *testing.T) {
t.Parallel()
const someName = "someName"
const someOtherName = "someOtherName"
d := FileData{
name: someName,
}
if d.Name() != someName {
t.Errorf("Failed to read correct Name, was %v", d.Name())
}
ChangeFileName(&d, someOtherName)
if d.Name() != someOtherName {
t.Errorf("Failed to set Name, was %v", d.Name())
}
go func() {
ChangeFileName(&d, someName)
}()
if d.Name() != someName && d.Name() != someOtherName {
t.Errorf("Failed to read either Name, was %v", d.Name())
}
}
func TestFileDataModTimeRace(t *testing.T) {
t.Parallel()
someTime := time.Now()
someOtherTime := someTime.Add(1 * time.Minute)
d := FileData{
modtime: someTime,
}
s := FileInfo{
FileData: &d,
}
if s.ModTime() != someTime {
t.Errorf("Failed to read correct value, was %v", s.ModTime())
}
SetModTime(&d, someOtherTime)
if s.ModTime() != someOtherTime {
t.Errorf("Failed to set ModTime, was %v", s.ModTime())
}
go func() {
SetModTime(&d, someTime)
}()
if s.ModTime() != someTime && s.ModTime() != someOtherTime {
t.Errorf("Failed to read either modtime, was %v", s.ModTime())
}
}
func TestFileDataModeRace(t *testing.T) {
t.Parallel()
const someMode = 0777
const someOtherMode = 0660
d := FileData{
mode: someMode,
}
s := FileInfo{
FileData: &d,
}
if s.Mode() != someMode {
t.Errorf("Failed to read correct value, was %v", s.Mode())
}
SetMode(&d, someOtherMode)
if s.Mode() != someOtherMode {
t.Errorf("Failed to set Mode, was %v", s.Mode())
}
go func() {
SetMode(&d, someMode)
}()
if s.Mode() != someMode && s.Mode() != someOtherMode {
t.Errorf("Failed to read either mode, was %v", s.Mode())
}
}
func TestFileDataIsDirRace(t *testing.T) {
t.Parallel()
d := FileData{
dir: true,
}
s := FileInfo{
FileData: &d,
}
if s.IsDir() != true {
t.Errorf("Failed to read correct value, was %v", s.IsDir())
}
go func() {
s.Lock()
d.dir = false
s.Unlock()
}()
//just logging the value to trigger a read:
t.Logf("Value is %v", s.IsDir())
}
func TestFileDataSizeRace(t *testing.T) {
t.Parallel()
const someData = "Hello"
const someOtherDataSize = "Hello World"
d := FileData{
data: []byte(someData),
dir: false,
}
s := FileInfo{
FileData: &d,
}
if s.Size() != int64(len(someData)) {
t.Errorf("Failed to read correct value, was %v", s.Size())
}
go func() {
s.Lock()
d.data = []byte(someOtherDataSize)
s.Unlock()
}()
//just logging the value to trigger a read:
t.Logf("Value is %v", s.Size())
//Testing the Dir size case
d.dir = true
if s.Size() != int64(42) {
t.Errorf("Failed to read correct value for dir, was %v", s.Size())
}
}

View file

@ -1,421 +0,0 @@
package afero
import (
"fmt"
"os"
"path/filepath"
"runtime"
"testing"
"time"
)
func TestNormalizePath(t *testing.T) {
type test struct {
input string
expected string
}
data := []test{
{".", FilePathSeparator},
{"./", FilePathSeparator},
{"..", FilePathSeparator},
{"../", FilePathSeparator},
{"./..", FilePathSeparator},
{"./../", FilePathSeparator},
}
for i, d := range data {
cpath := normalizePath(d.input)
if d.expected != cpath {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, cpath)
}
}
}
func TestPathErrors(t *testing.T) {
path := filepath.Join(".", "some", "path")
path2 := filepath.Join(".", "different", "path")
fs := NewMemMapFs()
perm := os.FileMode(0755)
// relevant functions:
// func (m *MemMapFs) Chmod(name string, mode os.FileMode) error
// func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error
// func (m *MemMapFs) Create(name string) (File, error)
// func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error
// func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error
// func (m *MemMapFs) Open(name string) (File, error)
// func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error)
// func (m *MemMapFs) Remove(name string) error
// func (m *MemMapFs) Rename(oldname, newname string) error
// func (m *MemMapFs) Stat(name string) (os.FileInfo, error)
err := fs.Chmod(path, perm)
checkPathError(t, err, "Chmod")
err = fs.Chtimes(path, time.Now(), time.Now())
checkPathError(t, err, "Chtimes")
// fs.Create doesn't return an error
err = fs.Mkdir(path2, perm)
if err != nil {
t.Error(err)
}
err = fs.Mkdir(path2, perm)
checkPathError(t, err, "Mkdir")
err = fs.MkdirAll(path2, perm)
if err != nil {
t.Error("MkdirAll:", err)
}
_, err = fs.Open(path)
checkPathError(t, err, "Open")
_, err = fs.OpenFile(path, os.O_RDWR, perm)
checkPathError(t, err, "OpenFile")
err = fs.Remove(path)
checkPathError(t, err, "Remove")
err = fs.RemoveAll(path)
if err != nil {
t.Error("RemoveAll:", err)
}
err = fs.Rename(path, path2)
checkPathError(t, err, "Rename")
_, err = fs.Stat(path)
checkPathError(t, err, "Stat")
}
func checkPathError(t *testing.T, err error, op string) {
pathErr, ok := err.(*os.PathError)
if !ok {
t.Error(op+":", err, "is not a os.PathError")
return
}
_, ok = pathErr.Err.(*os.PathError)
if ok {
t.Error(op+":", err, "contains another os.PathError")
}
}
// Ensure Permissions are set on OpenFile/Mkdir/MkdirAll
func TestPermSet(t *testing.T) {
const fileName = "/myFileTest"
const dirPath = "/myDirTest"
const dirPathAll = "/my/path/to/dir"
const fileMode = os.FileMode(0765)
// directories will also have the directory bit set
const dirMode = fileMode | os.ModeDir
fs := NewMemMapFs()
// Test Openfile
f, err := fs.OpenFile(fileName, os.O_CREATE, fileMode)
if err != nil {
t.Errorf("OpenFile Create failed: %s", err)
return
}
f.Close()
s, err := fs.Stat(fileName)
if err != nil {
t.Errorf("Stat failed: %s", err)
return
}
if s.Mode().String() != fileMode.String() {
t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), fileMode.String())
return
}
// Test Mkdir
err = fs.Mkdir(dirPath, dirMode)
if err != nil {
t.Errorf("MkDir Create failed: %s", err)
return
}
s, err = fs.Stat(dirPath)
if err != nil {
t.Errorf("Stat failed: %s", err)
return
}
// sets File
if s.Mode().String() != dirMode.String() {
t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String())
return
}
// Test MkdirAll
err = fs.MkdirAll(dirPathAll, dirMode)
if err != nil {
t.Errorf("MkDir Create failed: %s", err)
return
}
s, err = fs.Stat(dirPathAll)
if err != nil {
t.Errorf("Stat failed: %s", err)
return
}
if s.Mode().String() != dirMode.String() {
t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String())
return
}
}
// Fails if multiple file objects use the same file.at counter in MemMapFs
func TestMultipleOpenFiles(t *testing.T) {
defer removeAllTestFiles(t)
const fileName = "afero-demo2.txt"
var data = make([][]byte, len(Fss))
for i, fs := range Fss {
dir := testDir(fs)
path := filepath.Join(dir, fileName)
fh1, err := fs.Create(path)
if err != nil {
t.Error("fs.Create failed: " + err.Error())
}
_, err = fh1.Write([]byte("test"))
if err != nil {
t.Error("fh.Write failed: " + err.Error())
}
_, err = fh1.Seek(0, os.SEEK_SET)
if err != nil {
t.Error(err)
}
fh2, err := fs.OpenFile(path, os.O_RDWR, 0777)
if err != nil {
t.Error("fs.OpenFile failed: " + err.Error())
}
_, err = fh2.Seek(0, os.SEEK_END)
if err != nil {
t.Error(err)
}
_, err = fh2.Write([]byte("data"))
if err != nil {
t.Error(err)
}
err = fh2.Close()
if err != nil {
t.Error(err)
}
_, err = fh1.Write([]byte("data"))
if err != nil {
t.Error(err)
}
err = fh1.Close()
if err != nil {
t.Error(err)
}
// the file now should contain "datadata"
data[i], err = ReadFile(fs, path)
if err != nil {
t.Error(err)
}
}
for i, fs := range Fss {
if i == 0 {
continue
}
if string(data[0]) != string(data[i]) {
t.Errorf("%s and %s don't behave the same\n"+
"%s: \"%s\"\n%s: \"%s\"\n",
Fss[0].Name(), fs.Name(), Fss[0].Name(), data[0], fs.Name(), data[i])
}
}
}
// Test if file.Write() fails when opened as read only
func TestReadOnly(t *testing.T) {
defer removeAllTestFiles(t)
const fileName = "afero-demo.txt"
for _, fs := range Fss {
dir := testDir(fs)
path := filepath.Join(dir, fileName)
f, err := fs.Create(path)
if err != nil {
t.Error(fs.Name()+":", "fs.Create failed: "+err.Error())
}
_, err = f.Write([]byte("test"))
if err != nil {
t.Error(fs.Name()+":", "Write failed: "+err.Error())
}
f.Close()
f, err = fs.Open(path)
if err != nil {
t.Error("fs.Open failed: " + err.Error())
}
_, err = f.Write([]byte("data"))
if err == nil {
t.Error(fs.Name()+":", "No write error")
}
f.Close()
f, err = fs.OpenFile(path, os.O_RDONLY, 0644)
if err != nil {
t.Error("fs.Open failed: " + err.Error())
}
_, err = f.Write([]byte("data"))
if err == nil {
t.Error(fs.Name()+":", "No write error")
}
f.Close()
}
}
func TestWriteCloseTime(t *testing.T) {
defer removeAllTestFiles(t)
const fileName = "afero-demo.txt"
for _, fs := range Fss {
dir := testDir(fs)
path := filepath.Join(dir, fileName)
f, err := fs.Create(path)
if err != nil {
t.Error(fs.Name()+":", "fs.Create failed: "+err.Error())
}
f.Close()
f, err = fs.Create(path)
if err != nil {
t.Error(fs.Name()+":", "fs.Create failed: "+err.Error())
}
fi, err := f.Stat()
if err != nil {
t.Error(fs.Name()+":", "Stat failed: "+err.Error())
}
timeBefore := fi.ModTime()
// sorry for the delay, but we have to make sure time advances,
// also on non Un*x systems...
switch runtime.GOOS {
case "windows":
time.Sleep(2 * time.Second)
case "darwin":
time.Sleep(1 * time.Second)
default: // depending on the FS, this may work with < 1 second, on my old ext3 it does not
time.Sleep(1 * time.Second)
}
_, err = f.Write([]byte("test"))
if err != nil {
t.Error(fs.Name()+":", "Write failed: "+err.Error())
}
f.Close()
fi, err = fs.Stat(path)
if err != nil {
t.Error(fs.Name()+":", "fs.Stat failed: "+err.Error())
}
if fi.ModTime().Equal(timeBefore) {
t.Error(fs.Name()+":", "ModTime was not set on Close()")
}
}
}
// This test should be run with the race detector on:
// go test -race -v -timeout 10s -run TestRacingDeleteAndClose
func TestRacingDeleteAndClose(t *testing.T) {
fs := NewMemMapFs()
pathname := "testfile"
f, err := fs.Create(pathname)
if err != nil {
t.Fatal(err)
}
in := make(chan bool)
go func() {
<-in
f.Close()
}()
go func() {
<-in
fs.Remove(pathname)
}()
close(in)
}
// This test should be run with the race detector on:
// go test -run TestMemFsDataRace -race
func TestMemFsDataRace(t *testing.T) {
const dir = "test_dir"
fs := NewMemMapFs()
if err := fs.MkdirAll(dir, 0777); err != nil {
t.Fatal(err)
}
const n = 1000
done := make(chan struct{})
go func() {
defer close(done)
for i := 0; i < n; i++ {
fname := filepath.Join(dir, fmt.Sprintf("%d.txt", i))
if err := WriteFile(fs, fname, []byte(""), 0777); err != nil {
panic(err)
}
if err := fs.Remove(fname); err != nil {
panic(err)
}
}
}()
loop:
for {
select {
case <-done:
break loop
default:
_, err := ReadDir(fs, dir)
if err != nil {
t.Fatal(err)
}
}
}
}
func TestMemFsDirMode(t *testing.T) {
fs := NewMemMapFs()
err := fs.Mkdir("/testDir1", 0644)
if err != nil {
t.Error(err)
}
err = fs.MkdirAll("/sub/testDir2", 0644)
if err != nil {
t.Error(err)
}
info, err := fs.Stat("/testDir1")
if err != nil {
t.Error(err)
}
if !info.IsDir() {
t.Error("should be a directory")
}
if !info.Mode().IsDir() {
t.Error("FileMode is not directory")
}
info, err = fs.Stat("/sub/testDir2")
if err != nil {
t.Error(err)
}
if !info.IsDir() {
t.Error("should be a directory")
}
if !info.Mode().IsDir() {
t.Error("FileMode is not directory")
}
}

View file

@ -19,6 +19,8 @@ import (
"time"
)
var _ Lstater = (*OsFs)(nil)
// 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
@ -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 {
return os.Chtimes(name, atime, mtime)
}
func (OsFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
fi, err := os.Lstat(name)
return fi, true, err
}

View file

@ -60,7 +60,7 @@ func walk(fs Fs, path string, info os.FileInfo, walkFn filepath.WalkFunc) error
for _, name := range names {
filename := filepath.Join(path, name)
fileInfo, err := lstatIfOs(fs, filename)
fileInfo, err := lstatIfPossible(fs, filename)
if err != nil {
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
return err
@ -77,15 +77,13 @@ func walk(fs Fs, path string, info os.FileInfo, walkFn filepath.WalkFunc) error
return nil
}
// if the filesystem is OsFs use Lstat, else use fs.Stat
func lstatIfOs(fs Fs, path string) (info os.FileInfo, err error) {
_, ok := fs.(*OsFs)
if ok {
info, err = os.Lstat(path)
} else {
info, err = fs.Stat(path)
// if the filesystem supports it, use Lstat, else use fs.Stat
func lstatIfPossible(fs Fs, path string) (os.FileInfo, error) {
if lfs, ok := fs.(Lstater); ok {
fi, _, err := lfs.LstatIfPossible(path)
return fi, err
}
return
return fs.Stat(path)
}
// 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 {
info, err := lstatIfOs(fs, root)
info, err := lstatIfPossible(fs, root)
if err != nil {
return walkFn(root, nil, err)
}

View file

@ -1,69 +0,0 @@
// Copyright © 2014 Steve Francia <spf@spf13.com>.
// Copyright 2009 The Go Authors. All rights reserved.
//
// 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 (
"fmt"
"os"
"testing"
)
func TestWalk(t *testing.T) {
defer removeAllTestFiles(t)
var testDir string
for i, fs := range Fss {
if i == 0 {
testDir = setupTestDirRoot(t, fs)
} else {
setupTestDirReusePath(t, fs, testDir)
}
}
outputs := make([]string, len(Fss))
for i, fs := range Fss {
walkFn := func(path string, info os.FileInfo, err error) error {
if err != nil {
t.Error("walkFn err:", err)
}
var size int64
if !info.IsDir() {
size = info.Size()
}
outputs[i] += fmt.Sprintln(path, info.Name(), size, info.IsDir(), err)
return nil
}
err := Walk(fs, testDir, walkFn)
if err != nil {
t.Error(err)
}
}
fail := false
for i, o := range outputs {
if i == 0 {
continue
}
if o != outputs[i-1] {
fail = true
break
}
}
if fail {
t.Log("Walk outputs not equal!")
for i, o := range outputs {
t.Log(Fss[i].Name() + "\n" + o)
}
t.Fail()
}
}

View file

@ -6,6 +6,8 @@ import (
"time"
)
var _ Lstater = (*ReadOnlyFs)(nil)
type ReadOnlyFs struct {
source Fs
}
@ -34,6 +36,14 @@ func (r *ReadOnlyFs) Stat(name string) (os.FileInfo, error) {
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 {
return syscall.EPERM
}

View file

@ -1,96 +0,0 @@
package afero
import (
"regexp"
"testing"
)
func TestFilterReadOnly(t *testing.T) {
fs := &ReadOnlyFs{source: &MemMapFs{}}
_, err := fs.Create("/file.txt")
if err == nil {
t.Errorf("Did not fail to create file")
}
// t.Logf("ERR=%s", err)
}
func TestFilterReadonlyRemoveAndRead(t *testing.T) {
mfs := &MemMapFs{}
fh, err := mfs.Create("/file.txt")
fh.Write([]byte("content here"))
fh.Close()
fs := NewReadOnlyFs(mfs)
err = fs.Remove("/file.txt")
if err == nil {
t.Errorf("Did not fail to remove file")
}
fh, err = fs.Open("/file.txt")
if err != nil {
t.Errorf("Failed to open file: %s", err)
}
buf := make([]byte, len("content here"))
_, err = fh.Read(buf)
fh.Close()
if string(buf) != "content here" {
t.Errorf("Failed to read file: %s", err)
}
err = mfs.Remove("/file.txt")
if err != nil {
t.Errorf("Failed to remove file")
}
fh, err = fs.Open("/file.txt")
if err == nil {
fh.Close()
t.Errorf("File still present")
}
}
func TestFilterRegexp(t *testing.T) {
fs := NewRegexpFs(&MemMapFs{}, regexp.MustCompile(`\.txt$`))
_, err := fs.Create("/file.html")
if err == nil {
t.Errorf("Did not fail to create file")
}
// t.Logf("ERR=%s", err)
}
func TestFilterRORegexpChain(t *testing.T) {
rofs := &ReadOnlyFs{source: &MemMapFs{}}
fs := &RegexpFs{re: regexp.MustCompile(`\.txt$`), source: rofs}
_, err := fs.Create("/file.txt")
if err == nil {
t.Errorf("Did not fail to create file")
}
// t.Logf("ERR=%s", err)
}
func TestFilterRegexReadDir(t *testing.T) {
mfs := &MemMapFs{}
fs1 := &RegexpFs{re: regexp.MustCompile(`\.txt$`), source: mfs}
fs := &RegexpFs{re: regexp.MustCompile(`^a`), source: fs1}
mfs.MkdirAll("/dir/sub", 0777)
for _, name := range []string{"afile.txt", "afile.html", "bfile.txt"} {
for _, dir := range []string{"/dir/", "/dir/sub/"} {
fh, _ := mfs.Create(dir + name)
fh.Close()
}
}
files, _ := ReadDir(fs, "/dir")
if len(files) != 2 { // afile.txt, sub
t.Errorf("Got wrong number of files: %#v", files)
}
f, _ := fs.Open("/dir/sub")
names, _ := f.Readdirnames(-1)
if len(names) != 1 {
t.Errorf("Got wrong number of names: %v", names)
}
}

View file

@ -21,32 +21,33 @@ import (
// successful read in the overlay will move the cursor position in the base layer
// by the number of bytes read.
type UnionFile struct {
base File
layer File
off int
files []os.FileInfo
Base File
Layer File
Merger DirsMerger
off int
files []os.FileInfo
}
func (f *UnionFile) Close() error {
// 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
// -> cache would be useless ;-)
if f.base != nil {
f.base.Close()
if f.Base != nil {
f.Base.Close()
}
if f.layer != nil {
return f.layer.Close()
if f.Layer != nil {
return f.Layer.Close()
}
return BADFD
}
func (f *UnionFile) Read(s []byte) (int, error) {
if f.layer != nil {
n, err := f.layer.Read(s)
if (err == nil || err == io.EOF) && f.base != nil {
if f.Layer != nil {
n, err := f.Layer.Read(s)
if (err == nil || err == io.EOF) && f.Base != nil {
// 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)
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
// report an eventual io.EOF to the caller
err = seekErr
@ -54,105 +55,135 @@ func (f *UnionFile) Read(s []byte) (int, error) {
}
return n, err
}
if f.base != nil {
return f.base.Read(s)
if f.Base != nil {
return f.Base.Read(s)
}
return 0, BADFD
}
func (f *UnionFile) ReadAt(s []byte, o int64) (int, error) {
if f.layer != nil {
n, err := f.layer.ReadAt(s, o)
if (err == nil || err == io.EOF) && f.base != nil {
_, err = f.base.Seek(o+int64(n), os.SEEK_SET)
if f.Layer != nil {
n, err := f.Layer.ReadAt(s, o)
if (err == nil || err == io.EOF) && f.Base != nil {
_, err = f.Base.Seek(o+int64(n), os.SEEK_SET)
}
return n, err
}
if f.base != nil {
return f.base.ReadAt(s, o)
if f.Base != nil {
return f.Base.ReadAt(s, o)
}
return 0, BADFD
}
func (f *UnionFile) Seek(o int64, w int) (pos int64, err error) {
if f.layer != nil {
pos, err = f.layer.Seek(o, w)
if (err == nil || err == io.EOF) && f.base != nil {
_, err = f.base.Seek(o, w)
if f.Layer != nil {
pos, err = f.Layer.Seek(o, w)
if (err == nil || err == io.EOF) && f.Base != nil {
_, err = f.Base.Seek(o, w)
}
return pos, err
}
if f.base != nil {
return f.base.Seek(o, w)
if f.Base != nil {
return f.Base.Seek(o, w)
}
return 0, BADFD
}
func (f *UnionFile) Write(s []byte) (n int, err error) {
if f.layer != nil {
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?
_, err = f.base.Write(s)
if f.Layer != nil {
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?
_, err = f.Base.Write(s)
}
return n, err
}
if f.base != nil {
return f.base.Write(s)
if f.Base != nil {
return f.Base.Write(s)
}
return 0, BADFD
}
func (f *UnionFile) WriteAt(s []byte, o int64) (n int, err error) {
if f.layer != nil {
n, err = f.layer.WriteAt(s, o)
if err == nil && f.base != nil {
_, err = f.base.WriteAt(s, o)
if f.Layer != nil {
n, err = f.Layer.WriteAt(s, o)
if err == nil && f.Base != nil {
_, err = f.Base.WriteAt(s, o)
}
return n, err
}
if f.base != nil {
return f.base.WriteAt(s, o)
if f.Base != nil {
return f.Base.WriteAt(s, o)
}
return 0, BADFD
}
func (f *UnionFile) Name() string {
if f.layer != nil {
return f.layer.Name()
if f.Layer != nil {
return f.Layer.Name()
}
return f.base.Name()
return f.Base.Name()
}
// DirsMerger is how UnionFile weaves two directories together.
// It takes the FileInfo slices from the layer and the base and returns a
// single view.
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)
for _, fi := range lofi {
files[fi.Name()] = fi
}
for _, fi := range bofi {
if _, exists := files[fi.Name()]; !exists {
files[fi.Name()] = fi
}
}
rfi := make([]os.FileInfo, len(files))
i := 0
for _, fi := range files {
rfi[i] = fi
i++
}
return rfi, nil
}
// Readdir will weave the two directories together and
// return a single view of the overlayed directories
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 files = make(map[string]os.FileInfo)
var rfi []os.FileInfo
if f.layer != nil {
rfi, err = f.layer.Readdir(-1)
var lfi []os.FileInfo
if f.Layer != nil {
lfi, err = f.Layer.Readdir(-1)
if err != nil {
return nil, err
}
for _, fi := range rfi {
files[fi.Name()] = fi
}
}
if f.base != nil {
rfi, err = f.base.Readdir(-1)
var bfi []os.FileInfo
if f.Base != nil {
bfi, err = f.Base.Readdir(-1)
if err != nil {
return nil, err
}
for _, fi := range rfi {
if _, exists := files[fi.Name()]; !exists {
files[fi.Name()] = fi
}
}
}
for _, fi := range files {
f.files = append(f.files, fi)
merged, err := merge(lfi, bfi)
if err != nil {
return nil, err
}
f.files = append(f.files, merged...)
}
if c == -1 {
return f.files[f.off:], nil
@ -174,53 +205,53 @@ func (f *UnionFile) Readdirnames(c int) ([]string, error) {
}
func (f *UnionFile) Stat() (os.FileInfo, error) {
if f.layer != nil {
return f.layer.Stat()
if f.Layer != nil {
return f.Layer.Stat()
}
if f.base != nil {
return f.base.Stat()
if f.Base != nil {
return f.Base.Stat()
}
return nil, BADFD
}
func (f *UnionFile) Sync() (err error) {
if f.layer != nil {
err = f.layer.Sync()
if err == nil && f.base != nil {
err = f.base.Sync()
if f.Layer != nil {
err = f.Layer.Sync()
if err == nil && f.Base != nil {
err = f.Base.Sync()
}
return err
}
if f.base != nil {
return f.base.Sync()
if f.Base != nil {
return f.Base.Sync()
}
return BADFD
}
func (f *UnionFile) Truncate(s int64) (err error) {
if f.layer != nil {
err = f.layer.Truncate(s)
if err == nil && f.base != nil {
err = f.base.Truncate(s)
if f.Layer != nil {
err = f.Layer.Truncate(s)
if err == nil && f.Base != nil {
err = f.Base.Truncate(s)
}
return err
}
if f.base != nil {
return f.base.Truncate(s)
if f.Base != nil {
return f.Base.Truncate(s)
}
return BADFD
}
func (f *UnionFile) WriteString(s string) (n int, err error) {
if f.layer != nil {
n, err = f.layer.WriteString(s)
if err == nil && f.base != nil {
_, err = f.base.WriteString(s)
if f.Layer != nil {
n, err = f.Layer.WriteString(s)
if err == nil && f.Base != nil {
_, err = f.Base.WriteString(s)
}
return n, err
}
if f.base != nil {
return f.base.WriteString(s)
if f.Base != nil {
return f.Base.WriteString(s)
}
return 0, BADFD
}

View file

@ -20,7 +20,6 @@ import (
"bytes"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
@ -46,7 +45,7 @@ func WriteReader(fs Fs, path string, r io.Reader) (err error) {
err = fs.MkdirAll(ospath, 0777) // rwx, rw, r
if err != nil {
if err != os.ErrExist {
log.Panicln(err)
return err
}
}
}

View file

@ -1,450 +0,0 @@
// Copyright ©2015 Steve Francia <spf@spf13.com>
// Portions Copyright ©2015 The Hugo Authors
//
//
// 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 (
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
)
var testFS = new(MemMapFs)
func TestDirExists(t *testing.T) {
type test struct {
input string
expected bool
}
// First create a couple directories so there is something in the filesystem
//testFS := new(MemMapFs)
testFS.MkdirAll("/foo/bar", 0777)
data := []test{
{".", true},
{"./", true},
{"..", true},
{"../", true},
{"./..", true},
{"./../", true},
{"/foo/", true},
{"/foo", true},
{"/foo/bar", true},
{"/foo/bar/", true},
{"/", true},
{"/some-really-random-directory-name", false},
{"/some/really/random/directory/name", false},
{"./some-really-random-local-directory-name", false},
{"./some/really/random/local/directory/name", false},
}
for i, d := range data {
exists, _ := DirExists(testFS, filepath.FromSlash(d.input))
if d.expected != exists {
t.Errorf("Test %d %q failed. Expected %t got %t", i, d.input, d.expected, exists)
}
}
}
func TestIsDir(t *testing.T) {
testFS = new(MemMapFs)
type test struct {
input string
expected bool
}
data := []test{
{"./", true},
{"/", true},
{"./this-directory-does-not-existi", false},
{"/this-absolute-directory/does-not-exist", false},
}
for i, d := range data {
exists, _ := IsDir(testFS, d.input)
if d.expected != exists {
t.Errorf("Test %d failed. Expected %t got %t", i, d.expected, exists)
}
}
}
func TestIsEmpty(t *testing.T) {
testFS = new(MemMapFs)
zeroSizedFile, _ := createZeroSizedFileInTempDir()
defer deleteFileInTempDir(zeroSizedFile)
nonZeroSizedFile, _ := createNonZeroSizedFileInTempDir()
defer deleteFileInTempDir(nonZeroSizedFile)
emptyDirectory, _ := createEmptyTempDir()
defer deleteTempDir(emptyDirectory)
nonEmptyZeroLengthFilesDirectory, _ := createTempDirWithZeroLengthFiles()
defer deleteTempDir(nonEmptyZeroLengthFilesDirectory)
nonEmptyNonZeroLengthFilesDirectory, _ := createTempDirWithNonZeroLengthFiles()
defer deleteTempDir(nonEmptyNonZeroLengthFilesDirectory)
nonExistentFile := os.TempDir() + "/this-file-does-not-exist.txt"
nonExistentDir := os.TempDir() + "/this/direcotry/does/not/exist/"
fileDoesNotExist := fmt.Errorf("%q path does not exist", nonExistentFile)
dirDoesNotExist := fmt.Errorf("%q path does not exist", nonExistentDir)
type test struct {
input string
expectedResult bool
expectedErr error
}
data := []test{
{zeroSizedFile.Name(), true, nil},
{nonZeroSizedFile.Name(), false, nil},
{emptyDirectory, true, nil},
{nonEmptyZeroLengthFilesDirectory, false, nil},
{nonEmptyNonZeroLengthFilesDirectory, false, nil},
{nonExistentFile, false, fileDoesNotExist},
{nonExistentDir, false, dirDoesNotExist},
}
for i, d := range data {
exists, err := IsEmpty(testFS, d.input)
if d.expectedResult != exists {
t.Errorf("Test %d %q failed exists. Expected result %t got %t", i, d.input, d.expectedResult, exists)
}
if d.expectedErr != nil {
if d.expectedErr.Error() != err.Error() {
t.Errorf("Test %d failed with err. Expected %q(%#v) got %q(%#v)", i, d.expectedErr, d.expectedErr, err, err)
}
} else {
if d.expectedErr != err {
t.Errorf("Test %d failed. Expected error %q(%#v) got %q(%#v)", i, d.expectedErr, d.expectedErr, err, err)
}
}
}
}
func TestReaderContains(t *testing.T) {
for i, this := range []struct {
v1 string
v2 [][]byte
expect bool
}{
{"abc", [][]byte{[]byte("a")}, true},
{"abc", [][]byte{[]byte("b")}, true},
{"abcdefg", [][]byte{[]byte("efg")}, true},
{"abc", [][]byte{[]byte("d")}, false},
{"abc", [][]byte{[]byte("d"), []byte("e")}, false},
{"abc", [][]byte{[]byte("d"), []byte("a")}, true},
{"abc", [][]byte{[]byte("b"), []byte("e")}, true},
{"", nil, false},
{"", [][]byte{[]byte("a")}, false},
{"a", [][]byte{[]byte("")}, false},
{"", [][]byte{[]byte("")}, false}} {
result := readerContainsAny(strings.NewReader(this.v1), this.v2...)
if result != this.expect {
t.Errorf("[%d] readerContains: got %t but expected %t", i, result, this.expect)
}
}
if readerContainsAny(nil, []byte("a")) {
t.Error("readerContains with nil reader")
}
if readerContainsAny(nil, nil) {
t.Error("readerContains with nil arguments")
}
}
func createZeroSizedFileInTempDir() (File, error) {
filePrefix := "_path_test_"
f, e := TempFile(testFS, "", filePrefix) // dir is os.TempDir()
if e != nil {
// if there was an error no file was created.
// => no requirement to delete the file
return nil, e
}
return f, nil
}
func createNonZeroSizedFileInTempDir() (File, error) {
f, err := createZeroSizedFileInTempDir()
if err != nil {
// no file ??
}
byteString := []byte("byteString")
err = WriteFile(testFS, f.Name(), byteString, 0644)
if err != nil {
// delete the file
deleteFileInTempDir(f)
return nil, err
}
return f, nil
}
func deleteFileInTempDir(f File) {
err := testFS.Remove(f.Name())
if err != nil {
// now what?
}
}
func createEmptyTempDir() (string, error) {
dirPrefix := "_dir_prefix_"
d, e := TempDir(testFS, "", dirPrefix) // will be in os.TempDir()
if e != nil {
// no directory to delete - it was never created
return "", e
}
return d, nil
}
func createTempDirWithZeroLengthFiles() (string, error) {
d, dirErr := createEmptyTempDir()
if dirErr != nil {
//now what?
}
filePrefix := "_path_test_"
_, fileErr := TempFile(testFS, d, filePrefix) // dir is os.TempDir()
if fileErr != nil {
// if there was an error no file was created.
// but we need to remove the directory to clean-up
deleteTempDir(d)
return "", fileErr
}
// the dir now has one, zero length file in it
return d, nil
}
func createTempDirWithNonZeroLengthFiles() (string, error) {
d, dirErr := createEmptyTempDir()
if dirErr != nil {
//now what?
}
filePrefix := "_path_test_"
f, fileErr := TempFile(testFS, d, filePrefix) // dir is os.TempDir()
if fileErr != nil {
// if there was an error no file was created.
// but we need to remove the directory to clean-up
deleteTempDir(d)
return "", fileErr
}
byteString := []byte("byteString")
fileErr = WriteFile(testFS, f.Name(), byteString, 0644)
if fileErr != nil {
// delete the file
deleteFileInTempDir(f)
// also delete the directory
deleteTempDir(d)
return "", fileErr
}
// the dir now has one, zero length file in it
return d, nil
}
func TestExists(t *testing.T) {
zeroSizedFile, _ := createZeroSizedFileInTempDir()
defer deleteFileInTempDir(zeroSizedFile)
nonZeroSizedFile, _ := createNonZeroSizedFileInTempDir()
defer deleteFileInTempDir(nonZeroSizedFile)
emptyDirectory, _ := createEmptyTempDir()
defer deleteTempDir(emptyDirectory)
nonExistentFile := os.TempDir() + "/this-file-does-not-exist.txt"
nonExistentDir := os.TempDir() + "/this/direcotry/does/not/exist/"
type test struct {
input string
expectedResult bool
expectedErr error
}
data := []test{
{zeroSizedFile.Name(), true, nil},
{nonZeroSizedFile.Name(), true, nil},
{emptyDirectory, true, nil},
{nonExistentFile, false, nil},
{nonExistentDir, false, nil},
}
for i, d := range data {
exists, err := Exists(testFS, d.input)
if d.expectedResult != exists {
t.Errorf("Test %d failed. Expected result %t got %t", i, d.expectedResult, exists)
}
if d.expectedErr != err {
t.Errorf("Test %d failed. Expected %q got %q", i, d.expectedErr, err)
}
}
}
func TestSafeWriteToDisk(t *testing.T) {
emptyFile, _ := createZeroSizedFileInTempDir()
defer deleteFileInTempDir(emptyFile)
tmpDir, _ := createEmptyTempDir()
defer deleteTempDir(tmpDir)
randomString := "This is a random string!"
reader := strings.NewReader(randomString)
fileExists := fmt.Errorf("%v already exists", emptyFile.Name())
type test struct {
filename string
expectedErr error
}
now := time.Now().Unix()
nowStr := strconv.FormatInt(now, 10)
data := []test{
{emptyFile.Name(), fileExists},
{tmpDir + "/" + nowStr, nil},
}
for i, d := range data {
e := SafeWriteReader(testFS, d.filename, reader)
if d.expectedErr != nil {
if d.expectedErr.Error() != e.Error() {
t.Errorf("Test %d failed. Expected error %q but got %q", i, d.expectedErr.Error(), e.Error())
}
} else {
if d.expectedErr != e {
t.Errorf("Test %d failed. Expected %q but got %q", i, d.expectedErr, e)
}
contents, _ := ReadFile(testFS, d.filename)
if randomString != string(contents) {
t.Errorf("Test %d failed. Expected contents %q but got %q", i, randomString, string(contents))
}
}
reader.Seek(0, 0)
}
}
func TestWriteToDisk(t *testing.T) {
emptyFile, _ := createZeroSizedFileInTempDir()
defer deleteFileInTempDir(emptyFile)
tmpDir, _ := createEmptyTempDir()
defer deleteTempDir(tmpDir)
randomString := "This is a random string!"
reader := strings.NewReader(randomString)
type test struct {
filename string
expectedErr error
}
now := time.Now().Unix()
nowStr := strconv.FormatInt(now, 10)
data := []test{
{emptyFile.Name(), nil},
{tmpDir + "/" + nowStr, nil},
}
for i, d := range data {
e := WriteReader(testFS, d.filename, reader)
if d.expectedErr != e {
t.Errorf("Test %d failed. WriteToDisk Error Expected %q but got %q", i, d.expectedErr, e)
}
contents, e := ReadFile(testFS, d.filename)
if e != nil {
t.Errorf("Test %d failed. Could not read file %s. Reason: %s\n", i, d.filename, e)
}
if randomString != string(contents) {
t.Errorf("Test %d failed. Expected contents %q but got %q", i, randomString, string(contents))
}
reader.Seek(0, 0)
}
}
func TestGetTempDir(t *testing.T) {
dir := os.TempDir()
if FilePathSeparator != dir[len(dir)-1:] {
dir = dir + FilePathSeparator
}
testDir := "hugoTestFolder" + FilePathSeparator
tests := []struct {
input string
expected string
}{
{"", dir},
{testDir + " Foo bar ", dir + testDir + " Foo bar " + FilePathSeparator},
{testDir + "Foo.Bar/foo_Bar-Foo", dir + testDir + "Foo.Bar/foo_Bar-Foo" + FilePathSeparator},
{testDir + "fOO,bar:foo%bAR", dir + testDir + "fOObarfoo%bAR" + FilePathSeparator},
{testDir + "FOo/BaR.html", dir + testDir + "FOo/BaR.html" + FilePathSeparator},
{testDir + "трям/трям", dir + testDir + "трям/трям" + FilePathSeparator},
{testDir + "은행", dir + testDir + "은행" + FilePathSeparator},
{testDir + "Банковский кассир", dir + testDir + "Банковский кассир" + FilePathSeparator},
}
for _, test := range tests {
output := GetTempDir(new(MemMapFs), test.input)
if output != test.expected {
t.Errorf("Expected %#v, got %#v\n", test.expected, output)
}
}
}
// This function is very dangerous. Don't use it.
func deleteTempDir(d string) {
err := os.RemoveAll(d)
if err != nil {
// now what?
}
}
func TestFullBaseFsPath(t *testing.T) {
type dirSpec struct {
Dir1, Dir2, Dir3 string
}
dirSpecs := []dirSpec{
dirSpec{Dir1: "/", Dir2: "/", Dir3: "/"},
dirSpec{Dir1: "/", Dir2: "/path2", Dir3: "/"},
dirSpec{Dir1: "/path1/dir", Dir2: "/path2/dir/", Dir3: "/path3/dir"},
dirSpec{Dir1: "C:/path1", Dir2: "path2/dir", Dir3: "/path3/dir/"},
}
for _, ds := range dirSpecs {
memFs := NewMemMapFs()
level1Fs := NewBasePathFs(memFs, ds.Dir1)
level2Fs := NewBasePathFs(level1Fs, ds.Dir2)
level3Fs := NewBasePathFs(level2Fs, ds.Dir3)
type spec struct {
BaseFs Fs
FileName string
ExpectedPath string
}
specs := []spec{
spec{BaseFs: level3Fs, FileName: "f.txt", ExpectedPath: filepath.Join(ds.Dir1, ds.Dir2, ds.Dir3, "f.txt")},
spec{BaseFs: level3Fs, FileName: "", ExpectedPath: filepath.Join(ds.Dir1, ds.Dir2, ds.Dir3, "")},
spec{BaseFs: level2Fs, FileName: "f.txt", ExpectedPath: filepath.Join(ds.Dir1, ds.Dir2, "f.txt")},
spec{BaseFs: level2Fs, FileName: "", ExpectedPath: filepath.Join(ds.Dir1, ds.Dir2, "")},
spec{BaseFs: level1Fs, FileName: "f.txt", ExpectedPath: filepath.Join(ds.Dir1, "f.txt")},
spec{BaseFs: level1Fs, FileName: "", ExpectedPath: filepath.Join(ds.Dir1, "")},
}
for _, s := range specs {
if actualPath := FullBaseFsPath(s.BaseFs.(*BasePathFs), s.FileName); actualPath != s.ExpectedPath {
t.Errorf("Expected \n%s got \n%s", s.ExpectedPath, actualPath)
}
}
}
}

View file

@ -1,215 +0,0 @@
package pflag
import (
"fmt"
"strconv"
"strings"
"testing"
)
func setUpBSFlagSet(bsp *[]bool) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.BoolSliceVar(bsp, "bs", []bool{}, "Command separated list!")
return f
}
func setUpBSFlagSetWithDefault(bsp *[]bool) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.BoolSliceVar(bsp, "bs", []bool{false, true}, "Command separated list!")
return f
}
func TestEmptyBS(t *testing.T) {
var bs []bool
f := setUpBSFlagSet(&bs)
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
getBS, err := f.GetBoolSlice("bs")
if err != nil {
t.Fatal("got an error from GetBoolSlice():", err)
}
if len(getBS) != 0 {
t.Fatalf("got bs %v with len=%d but expected length=0", getBS, len(getBS))
}
}
func TestBS(t *testing.T) {
var bs []bool
f := setUpBSFlagSet(&bs)
vals := []string{"1", "F", "TRUE", "0"}
arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ","))
err := f.Parse([]string{arg})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range bs {
b, err := strconv.ParseBool(vals[i])
if err != nil {
t.Fatalf("got error: %v", err)
}
if b != v {
t.Fatalf("expected is[%d] to be %s but got: %t", i, vals[i], v)
}
}
getBS, err := f.GetBoolSlice("bs")
if err != nil {
t.Fatalf("got error: %v", err)
}
for i, v := range getBS {
b, err := strconv.ParseBool(vals[i])
if err != nil {
t.Fatalf("got error: %v", err)
}
if b != v {
t.Fatalf("expected bs[%d] to be %s but got: %t from GetBoolSlice", i, vals[i], v)
}
}
}
func TestBSDefault(t *testing.T) {
var bs []bool
f := setUpBSFlagSetWithDefault(&bs)
vals := []string{"false", "T"}
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range bs {
b, err := strconv.ParseBool(vals[i])
if err != nil {
t.Fatalf("got error: %v", err)
}
if b != v {
t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v)
}
}
getBS, err := f.GetBoolSlice("bs")
if err != nil {
t.Fatal("got an error from GetBoolSlice():", err)
}
for i, v := range getBS {
b, err := strconv.ParseBool(vals[i])
if err != nil {
t.Fatal("got an error from GetBoolSlice():", err)
}
if b != v {
t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v)
}
}
}
func TestBSWithDefault(t *testing.T) {
var bs []bool
f := setUpBSFlagSetWithDefault(&bs)
vals := []string{"FALSE", "1"}
arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ","))
err := f.Parse([]string{arg})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range bs {
b, err := strconv.ParseBool(vals[i])
if err != nil {
t.Fatalf("got error: %v", err)
}
if b != v {
t.Fatalf("expected bs[%d] to be %t but got: %t", i, b, v)
}
}
getBS, err := f.GetBoolSlice("bs")
if err != nil {
t.Fatal("got an error from GetBoolSlice():", err)
}
for i, v := range getBS {
b, err := strconv.ParseBool(vals[i])
if err != nil {
t.Fatalf("got error: %v", err)
}
if b != v {
t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v)
}
}
}
func TestBSCalledTwice(t *testing.T) {
var bs []bool
f := setUpBSFlagSet(&bs)
in := []string{"T,F", "T"}
expected := []bool{true, false, true}
argfmt := "--bs=%s"
arg1 := fmt.Sprintf(argfmt, in[0])
arg2 := fmt.Sprintf(argfmt, in[1])
err := f.Parse([]string{arg1, arg2})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range bs {
if expected[i] != v {
t.Fatalf("expected bs[%d] to be %t but got %t", i, expected[i], v)
}
}
}
func TestBSBadQuoting(t *testing.T) {
tests := []struct {
Want []bool
FlagArg []string
}{
{
Want: []bool{true, false, true},
FlagArg: []string{"1", "0", "true"},
},
{
Want: []bool{true, false},
FlagArg: []string{"True", "F"},
},
{
Want: []bool{true, false},
FlagArg: []string{"T", "0"},
},
{
Want: []bool{true, false},
FlagArg: []string{"1", "0"},
},
{
Want: []bool{true, false, false},
FlagArg: []string{"true,false", "false"},
},
{
Want: []bool{true, false, false, true, false, true, false},
FlagArg: []string{`"true,false,false,1,0, T"`, " false "},
},
{
Want: []bool{false, false, true, false, true, false, true},
FlagArg: []string{`"0, False, T,false , true,F"`, "true"},
},
}
for i, test := range tests {
var bs []bool
f := setUpBSFlagSet(&bs)
if err := f.Parse([]string{fmt.Sprintf("--bs=%s", strings.Join(test.FlagArg, ","))}); err != nil {
t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%#v",
err, test.FlagArg, test.Want[i])
}
for j, b := range bs {
if b != test.Want[j] {
t.Fatalf("bad value parsed for test %d on bool %d:\nwant:\t%t\ngot:\t%t", i, j, test.Want[j], b)
}
}
}
}

View file

@ -1,179 +0,0 @@
// Copyright 2009 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 pflag
import (
"bytes"
"strconv"
"testing"
)
// This value can be a boolean ("true", "false") or "maybe"
type triStateValue int
const (
triStateFalse triStateValue = 0
triStateTrue triStateValue = 1
triStateMaybe triStateValue = 2
)
const strTriStateMaybe = "maybe"
func (v *triStateValue) IsBoolFlag() bool {
return true
}
func (v *triStateValue) Get() interface{} {
return triStateValue(*v)
}
func (v *triStateValue) Set(s string) error {
if s == strTriStateMaybe {
*v = triStateMaybe
return nil
}
boolVal, err := strconv.ParseBool(s)
if boolVal {
*v = triStateTrue
} else {
*v = triStateFalse
}
return err
}
func (v *triStateValue) String() string {
if *v == triStateMaybe {
return strTriStateMaybe
}
return strconv.FormatBool(*v == triStateTrue)
}
// The type of the flag as required by the pflag.Value interface
func (v *triStateValue) Type() string {
return "version"
}
func setUpFlagSet(tristate *triStateValue) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
*tristate = triStateFalse
flag := f.VarPF(tristate, "tristate", "t", "tristate value (true, maybe or false)")
flag.NoOptDefVal = "true"
return f
}
func TestExplicitTrue(t *testing.T) {
var tristate triStateValue
f := setUpFlagSet(&tristate)
err := f.Parse([]string{"--tristate=true"})
if err != nil {
t.Fatal("expected no error; got", err)
}
if tristate != triStateTrue {
t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
}
}
func TestImplicitTrue(t *testing.T) {
var tristate triStateValue
f := setUpFlagSet(&tristate)
err := f.Parse([]string{"--tristate"})
if err != nil {
t.Fatal("expected no error; got", err)
}
if tristate != triStateTrue {
t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
}
}
func TestShortFlag(t *testing.T) {
var tristate triStateValue
f := setUpFlagSet(&tristate)
err := f.Parse([]string{"-t"})
if err != nil {
t.Fatal("expected no error; got", err)
}
if tristate != triStateTrue {
t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
}
}
func TestShortFlagExtraArgument(t *testing.T) {
var tristate triStateValue
f := setUpFlagSet(&tristate)
// The"maybe"turns into an arg, since short boolean options will only do true/false
err := f.Parse([]string{"-t", "maybe"})
if err != nil {
t.Fatal("expected no error; got", err)
}
if tristate != triStateTrue {
t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
}
args := f.Args()
if len(args) != 1 || args[0] != "maybe" {
t.Fatal("expected an extra 'maybe' argument to stick around")
}
}
func TestExplicitMaybe(t *testing.T) {
var tristate triStateValue
f := setUpFlagSet(&tristate)
err := f.Parse([]string{"--tristate=maybe"})
if err != nil {
t.Fatal("expected no error; got", err)
}
if tristate != triStateMaybe {
t.Fatal("expected", triStateMaybe, "(triStateMaybe) but got", tristate, "instead")
}
}
func TestExplicitFalse(t *testing.T) {
var tristate triStateValue
f := setUpFlagSet(&tristate)
err := f.Parse([]string{"--tristate=false"})
if err != nil {
t.Fatal("expected no error; got", err)
}
if tristate != triStateFalse {
t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead")
}
}
func TestImplicitFalse(t *testing.T) {
var tristate triStateValue
f := setUpFlagSet(&tristate)
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
if tristate != triStateFalse {
t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead")
}
}
func TestInvalidValue(t *testing.T) {
var tristate triStateValue
f := setUpFlagSet(&tristate)
var buf bytes.Buffer
f.SetOutput(&buf)
err := f.Parse([]string{"--tristate=invalid"})
if err == nil {
t.Fatal("expected an error but did not get any, tristate has value", tristate)
}
}
func TestBoolP(t *testing.T) {
b := BoolP("bool", "b", false, "bool value in CommandLine")
c := BoolP("c", "c", false, "other bool value")
args := []string{"--bool"}
if err := CommandLine.Parse(args); err != nil {
t.Error("expected no error, got ", err)
}
if *b != true {
t.Errorf("expected b=true got b=%v", *b)
}
if *c != false {
t.Errorf("expect c=false got c=%v", *c)
}
}

105
vendor/github.com/spf13/pflag/bytes.go generated vendored Normal file
View file

@ -0,0 +1,105 @@
package pflag
import (
"encoding/hex"
"fmt"
"strings"
)
// BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded
type bytesHexValue []byte
func (bytesHex bytesHexValue) String() string {
return fmt.Sprintf("%X", []byte(bytesHex))
}
func (bytesHex *bytesHexValue) Set(value string) error {
bin, err := hex.DecodeString(strings.TrimSpace(value))
if err != nil {
return err
}
*bytesHex = bin
return nil
}
func (*bytesHexValue) Type() string {
return "bytesHex"
}
func newBytesHexValue(val []byte, p *[]byte) *bytesHexValue {
*p = val
return (*bytesHexValue)(p)
}
func bytesHexConv(sval string) (interface{}, error) {
bin, err := hex.DecodeString(sval)
if err == nil {
return bin, nil
}
return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err)
}
// GetBytesHex return the []byte value of a flag with the given name
func (f *FlagSet) GetBytesHex(name string) ([]byte, error) {
val, err := f.getFlagType(name, "bytesHex", bytesHexConv)
if err != nil {
return []byte{}, err
}
return val.([]byte), nil
}
// BytesHexVar defines an []byte flag with specified name, default value, and usage string.
// The argument p points to an []byte variable in which to store the value of the flag.
func (f *FlagSet) BytesHexVar(p *[]byte, name string, value []byte, usage string) {
f.VarP(newBytesHexValue(value, p), name, "", usage)
}
// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
f.VarP(newBytesHexValue(value, p), name, shorthand, usage)
}
// BytesHexVar defines an []byte flag with specified name, default value, and usage string.
// The argument p points to an []byte variable in which to store the value of the flag.
func BytesHexVar(p *[]byte, name string, value []byte, usage string) {
CommandLine.VarP(newBytesHexValue(value, p), name, "", usage)
}
// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
func BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
CommandLine.VarP(newBytesHexValue(value, p), name, shorthand, usage)
}
// BytesHex defines an []byte flag with specified name, default value, and usage string.
// The return value is the address of an []byte variable that stores the value of the flag.
func (f *FlagSet) BytesHex(name string, value []byte, usage string) *[]byte {
p := new([]byte)
f.BytesHexVarP(p, name, "", value, usage)
return p
}
// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
p := new([]byte)
f.BytesHexVarP(p, name, shorthand, value, usage)
return p
}
// BytesHex defines an []byte flag with specified name, default value, and usage string.
// The return value is the address of an []byte variable that stores the value of the flag.
func BytesHex(name string, value []byte, usage string) *[]byte {
return CommandLine.BytesHexP(name, "", value, usage)
}
// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
return CommandLine.BytesHexP(name, shorthand, value, usage)
}

View file

@ -11,13 +11,13 @@ func newCountValue(val int, p *int) *countValue {
}
func (i *countValue) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 64)
// -1 means that no specific value was passed, so increment
if v == -1 {
// "+1" means that no specific value was passed, so increment
if s == "+1" {
*i = countValue(*i + 1)
} else {
*i = countValue(v)
return nil
}
v, err := strconv.ParseInt(s, 0, 0)
*i = countValue(v)
return err
}
@ -54,7 +54,7 @@ func (f *FlagSet) CountVar(p *int, name string, usage string) {
// CountVarP is like CountVar only take a shorthand for the flag name.
func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) {
flag := f.VarPF(newCountValue(0, p), name, shorthand, usage)
flag.NoOptDefVal = "-1"
flag.NoOptDefVal = "+1"
}
// CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set

View file

@ -1,52 +0,0 @@
package pflag
import (
"os"
"testing"
)
func setUpCount(c *int) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.CountVarP(c, "verbose", "v", "a counter")
return f
}
func TestCount(t *testing.T) {
testCases := []struct {
input []string
success bool
expected int
}{
{[]string{"-vvv"}, true, 3},
{[]string{"-v", "-v", "-v"}, true, 3},
{[]string{"-v", "--verbose", "-v"}, true, 3},
{[]string{"-v=3", "-v"}, true, 4},
{[]string{"-v=a"}, false, 0},
}
devnull, _ := os.Open(os.DevNull)
os.Stderr = devnull
for i := range testCases {
var count int
f := setUpCount(&count)
tc := &testCases[i]
err := f.Parse(tc.input)
if err != nil && tc.success == true {
t.Errorf("expected success, got %q", err)
continue
} else if err == nil && tc.success == false {
t.Errorf("expected failure, got success")
continue
} else if tc.success {
c, err := f.GetCount("verbose")
if err != nil {
t.Errorf("Got error trying to fetch the counter flag")
}
if c != tc.expected {
t.Errorf("expected %q, got %q", tc.expected, c)
}
}
}
}

128
vendor/github.com/spf13/pflag/duration_slice.go generated vendored Normal file
View file

@ -0,0 +1,128 @@
package pflag
import (
"fmt"
"strings"
"time"
)
// -- durationSlice Value
type durationSliceValue struct {
value *[]time.Duration
changed bool
}
func newDurationSliceValue(val []time.Duration, p *[]time.Duration) *durationSliceValue {
dsv := new(durationSliceValue)
dsv.value = p
*dsv.value = val
return dsv
}
func (s *durationSliceValue) Set(val string) error {
ss := strings.Split(val, ",")
out := make([]time.Duration, len(ss))
for i, d := range ss {
var err error
out[i], err = time.ParseDuration(d)
if err != nil {
return err
}
}
if !s.changed {
*s.value = out
} else {
*s.value = append(*s.value, out...)
}
s.changed = true
return nil
}
func (s *durationSliceValue) Type() string {
return "durationSlice"
}
func (s *durationSliceValue) String() string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = fmt.Sprintf("%s", d)
}
return "[" + strings.Join(out, ",") + "]"
}
func durationSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []time.Duration{}, nil
}
ss := strings.Split(val, ",")
out := make([]time.Duration, len(ss))
for i, d := range ss {
var err error
out[i], err = time.ParseDuration(d)
if err != nil {
return nil, err
}
}
return out, nil
}
// GetDurationSlice returns the []time.Duration value of a flag with the given name
func (f *FlagSet) GetDurationSlice(name string) ([]time.Duration, error) {
val, err := f.getFlagType(name, "durationSlice", durationSliceConv)
if err != nil {
return []time.Duration{}, err
}
return val.([]time.Duration), nil
}
// DurationSliceVar defines a durationSlice flag with specified name, default value, and usage string.
// The argument p points to a []time.Duration variable in which to store the value of the flag.
func (f *FlagSet) DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) {
f.VarP(newDurationSliceValue(value, p), name, "", usage)
}
// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) {
f.VarP(newDurationSliceValue(value, p), name, shorthand, usage)
}
// DurationSliceVar defines a duration[] flag with specified name, default value, and usage string.
// The argument p points to a duration[] variable in which to store the value of the flag.
func DurationSliceVar(p *[]time.Duration, name string, value []time.Duration, usage string) {
CommandLine.VarP(newDurationSliceValue(value, p), name, "", usage)
}
// DurationSliceVarP is like DurationSliceVar, but accepts a shorthand letter that can be used after a single dash.
func DurationSliceVarP(p *[]time.Duration, name, shorthand string, value []time.Duration, usage string) {
CommandLine.VarP(newDurationSliceValue(value, p), name, shorthand, usage)
}
// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string.
// The return value is the address of a []time.Duration variable that stores the value of the flag.
func (f *FlagSet) DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration {
p := []time.Duration{}
f.DurationSliceVarP(&p, name, "", value, usage)
return &p
}
// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration {
p := []time.Duration{}
f.DurationSliceVarP(&p, name, shorthand, value, usage)
return &p
}
// DurationSlice defines a []time.Duration flag with specified name, default value, and usage string.
// The return value is the address of a []time.Duration variable that stores the value of the flag.
func DurationSlice(name string, value []time.Duration, usage string) *[]time.Duration {
return CommandLine.DurationSliceP(name, "", value, usage)
}
// DurationSliceP is like DurationSlice, but accepts a shorthand letter that can be used after a single dash.
func DurationSliceP(name, shorthand string, value []time.Duration, usage string) *[]time.Duration {
return CommandLine.DurationSliceP(name, shorthand, value, usage)
}

View file

@ -1,36 +0,0 @@
// Copyright 2012 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 pflag_test
import (
"fmt"
"github.com/spf13/pflag"
)
func ExampleShorthandLookup() {
name := "verbose"
short := name[:1]
pflag.BoolP(name, short, false, "verbose output")
// len(short) must be == 1
flag := pflag.ShorthandLookup(short)
fmt.Println(flag.Name)
}
func ExampleFlagSet_ShorthandLookup() {
name := "verbose"
short := name[:1]
fs := pflag.NewFlagSet("Example", pflag.ContinueOnError)
fs.BoolP(name, short, false, "verbose output")
// len(short) must be == 1
flag := fs.ShorthandLookup(short)
fmt.Println(flag.Name)
}

View file

@ -1,29 +0,0 @@
// Copyright 2010 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 pflag
import (
"io/ioutil"
"os"
)
// Additional routines compiled into the package only during testing.
// ResetForTesting clears all flag state and sets the usage function as directed.
// After calling ResetForTesting, parse errors in flag handling will not
// exit the program.
func ResetForTesting(usage func()) {
CommandLine = &FlagSet{
name: os.Args[0],
errorHandling: ContinueOnError,
output: ioutil.Discard,
}
Usage = usage
}
// GetCommandLine returns the default FlagSet.
func GetCommandLine() *FlagSet {
return CommandLine
}

155
vendor/github.com/spf13/pflag/flag.go generated vendored
View file

@ -101,6 +101,7 @@ package pflag
import (
"bytes"
"errors"
goflag "flag"
"fmt"
"io"
"os"
@ -123,6 +124,12 @@ const (
PanicOnError
)
// ParseErrorsWhitelist defines the parsing errors that can be ignored
type ParseErrorsWhitelist struct {
// UnknownFlags will ignore unknown flags errors and continue parsing rest of the flags
UnknownFlags bool
}
// NormalizedName is a flag name that has been normalized according to rules
// for the FlagSet (e.g. making '-' and '_' equivalent).
type NormalizedName string
@ -138,6 +145,9 @@ type FlagSet struct {
// help/usage messages.
SortFlags bool
// ParseErrorsWhitelist is used to configure a whitelist of errors
ParseErrorsWhitelist ParseErrorsWhitelist
name string
parsed bool
actual map[NormalizedName]*Flag
@ -153,6 +163,8 @@ type FlagSet struct {
output io.Writer // nil means stderr; use out() accessor
interspersed bool // allow interspersed option/non-option args
normalizeNameFunc func(f *FlagSet, name string) NormalizedName
addedGoFlagSets []*goflag.FlagSet
}
// A Flag represents the state of a flag.
@ -202,12 +214,18 @@ func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
f.normalizeNameFunc = n
f.sortedFormal = f.sortedFormal[:0]
for k, v := range f.orderedFormal {
delete(f.formal, NormalizedName(v.Name))
nname := f.normalizeFlagName(v.Name)
v.Name = string(nname)
f.formal[nname] = v
f.orderedFormal[k] = v
for fname, flag := range f.formal {
nname := f.normalizeFlagName(flag.Name)
if fname == nname {
continue
}
flag.Name = string(nname)
delete(f.formal, fname)
f.formal[nname] = flag
if _, set := f.actual[fname]; set {
delete(f.actual, fname)
f.actual[nname] = flag
}
}
}
@ -261,16 +279,16 @@ func (f *FlagSet) VisitAll(fn func(*Flag)) {
}
}
// HasFlags returns a bool to indicate if the FlagSet has any flags definied.
// HasFlags returns a bool to indicate if the FlagSet has any flags defined.
func (f *FlagSet) HasFlags() bool {
return len(f.formal) > 0
}
// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags
// definied that are not hidden or deprecated.
// that are not hidden.
func (f *FlagSet) HasAvailableFlags() bool {
for _, flag := range f.formal {
if !flag.Hidden && len(flag.Deprecated) == 0 {
if !flag.Hidden {
return true
}
}
@ -380,6 +398,7 @@ func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error {
return fmt.Errorf("deprecated message for flag %q must be set", name)
}
flag.Deprecated = usageMessage
flag.Hidden = true
return nil
}
@ -440,13 +459,15 @@ func (f *FlagSet) Set(name, value string) error {
return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err)
}
if f.actual == nil {
f.actual = make(map[NormalizedName]*Flag)
}
f.actual[normalName] = flag
f.orderedActual = append(f.orderedActual, flag)
if !flag.Changed {
if f.actual == nil {
f.actual = make(map[NormalizedName]*Flag)
}
f.actual[normalName] = flag
f.orderedActual = append(f.orderedActual, flag)
flag.Changed = true
flag.Changed = true
}
if flag.Deprecated != "" {
fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
@ -556,6 +577,14 @@ func UnquoteUsage(flag *Flag) (name string, usage string) {
name = "int"
case "uint64":
name = "uint"
case "stringSlice":
name = "strings"
case "intSlice":
name = "ints"
case "uintSlice":
name = "uints"
case "boolSlice":
name = "bools"
}
return
@ -570,11 +599,14 @@ func wrapN(i, slop int, s string) (string, string) {
return s, ""
}
w := strings.LastIndexAny(s[:i], " \t")
w := strings.LastIndexAny(s[:i], " \t\n")
if w <= 0 {
return s, ""
}
nlPos := strings.LastIndex(s[:i], "\n")
if nlPos > 0 && nlPos < w {
return s[:nlPos], s[nlPos+1:]
}
return s[:w], s[w+1:]
}
@ -583,7 +615,7 @@ func wrapN(i, slop int, s string) (string, string) {
// caller). Pass `w` == 0 to do no wrapping
func wrap(i, w int, s string) string {
if w == 0 {
return s
return strings.Replace(s, "\n", "\n"+strings.Repeat(" ", i), -1)
}
// space between indent i and end of line width w into which
@ -601,7 +633,7 @@ func wrap(i, w int, s string) string {
}
// If still not enough space then don't even try to wrap.
if wrap < 24 {
return s
return strings.Replace(s, "\n", r, -1)
}
// Try to avoid short orphan words on the final line, by
@ -613,14 +645,14 @@ func wrap(i, w int, s string) string {
// Handle first line, which is indented by the caller (or the
// special case above)
l, s = wrapN(wrap, slop, s)
r = r + l
r = r + strings.Replace(l, "\n", "\n"+strings.Repeat(" ", i), -1)
// Now wrap the rest
for s != "" {
var t string
t, s = wrapN(wrap, slop, s)
r = r + "\n" + strings.Repeat(" ", i) + t
r = r + "\n" + strings.Repeat(" ", i) + strings.Replace(t, "\n", "\n"+strings.Repeat(" ", i), -1)
}
return r
@ -637,7 +669,7 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
maxlen := 0
f.VisitAll(func(flag *Flag) {
if flag.Deprecated != "" || flag.Hidden {
if flag.Hidden {
return
}
@ -660,6 +692,10 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
if flag.NoOptDefVal != "true" {
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
}
case "count":
if flag.NoOptDefVal != "+1" {
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
}
default:
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
}
@ -680,6 +716,9 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
line += fmt.Sprintf(" (default %s)", flag.DefValue)
}
}
if len(flag.Deprecated) != 0 {
line += fmt.Sprintf(" (DEPRECATED: %s)", flag.Deprecated)
}
lines = append(lines, line)
})
@ -857,8 +896,10 @@ func VarP(value Value, name, shorthand, usage string) {
// returns the error.
func (f *FlagSet) failf(format string, a ...interface{}) error {
err := fmt.Errorf(format, a...)
fmt.Fprintln(f.out(), err)
f.usage()
if f.errorHandling != ContinueOnError {
fmt.Fprintln(f.out(), err)
f.usage()
}
return err
}
@ -874,6 +915,25 @@ func (f *FlagSet) usage() {
}
}
//--unknown (args will be empty)
//--unknown --next-flag ... (args will be --next-flag ...)
//--unknown arg ... (args will be arg ...)
func stripUnknownFlagValue(args []string) []string {
if len(args) == 0 {
//--unknown
return args
}
first := args[0]
if first[0] == '-' {
//--unknown --next-flag ...
return args
}
//--unknown arg ... (args will be arg ...)
return args[1:]
}
func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) {
a = args
name := s[2:]
@ -885,13 +945,24 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
split := strings.SplitN(name, "=", 2)
name = split[0]
flag, exists := f.formal[f.normalizeFlagName(name)]
if !exists {
if name == "help" { // special case for nice help message.
switch {
case name == "help":
f.usage()
return a, ErrHelp
case f.ParseErrorsWhitelist.UnknownFlags:
// --unknown=unknownval arg ...
// we do not want to lose arg in this case
if len(split) >= 2 {
return a, nil
}
return stripUnknownFlagValue(a), nil
default:
err = f.failf("unknown flag: --%s", name)
return
}
err = f.failf("unknown flag: --%s", name)
return
}
var value string
@ -912,6 +983,9 @@ func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []strin
}
err = fn(flag, value)
if err != nil {
f.failf(err.Error())
}
return
}
@ -926,13 +1000,25 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse
flag, exists := f.shorthands[c]
if !exists {
if c == 'h' { // special case for nice help message.
switch {
case c == 'h':
f.usage()
err = ErrHelp
return
case f.ParseErrorsWhitelist.UnknownFlags:
// '-f=arg arg ...'
// we do not want to lose arg in this case
if len(shorthands) > 2 && shorthands[1] == '=' {
outShorts = ""
return
}
outArgs = stripUnknownFlagValue(outArgs)
return
default:
err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
return
}
err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
return
}
var value string
@ -962,6 +1048,9 @@ func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parse
}
err = fn(flag, value)
if err != nil {
f.failf(err.Error())
}
return
}
@ -1016,6 +1105,11 @@ func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) {
// are defined and before flags are accessed by the program.
// The return value will be ErrHelp if -help was set but not defined.
func (f *FlagSet) Parse(arguments []string) error {
if f.addedGoFlagSets != nil {
for _, goFlagSet := range f.addedGoFlagSets {
goFlagSet.Parse(nil)
}
}
f.parsed = true
if len(arguments) < 0 {
@ -1034,6 +1128,7 @@ func (f *FlagSet) Parse(arguments []string) error {
case ContinueOnError:
return err
case ExitOnError:
fmt.Println(err)
os.Exit(2)
case PanicOnError:
panic(err)

File diff suppressed because it is too large Load diff

View file

@ -98,4 +98,8 @@ func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) {
newSet.VisitAll(func(goflag *goflag.Flag) {
f.AddGoFlag(goflag)
})
if f.addedGoFlagSets == nil {
f.addedGoFlagSets = make([]*goflag.FlagSet, 0)
}
f.addedGoFlagSets = append(f.addedGoFlagSets, newSet)
}

View file

@ -1,39 +0,0 @@
// Copyright 2009 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 pflag
import (
goflag "flag"
"testing"
)
func TestGoflags(t *testing.T) {
goflag.String("stringFlag", "stringFlag", "stringFlag")
goflag.Bool("boolFlag", false, "boolFlag")
f := NewFlagSet("test", ContinueOnError)
f.AddGoFlagSet(goflag.CommandLine)
err := f.Parse([]string{"--stringFlag=bob", "--boolFlag"})
if err != nil {
t.Fatal("expected no error; get", err)
}
getString, err := f.GetString("stringFlag")
if err != nil {
t.Fatal("expected no error; get", err)
}
if getString != "bob" {
t.Fatalf("expected getString=bob but got getString=%s", getString)
}
getBool, err := f.GetBool("boolFlag")
if err != nil {
t.Fatal("expected no error; get", err)
}
if getBool != true {
t.Fatalf("expected getBool=true but got getBool=%v", getBool)
}
}

88
vendor/github.com/spf13/pflag/int16.go generated vendored Normal file
View file

@ -0,0 +1,88 @@
package pflag
import "strconv"
// -- int16 Value
type int16Value int16
func newInt16Value(val int16, p *int16) *int16Value {
*p = val
return (*int16Value)(p)
}
func (i *int16Value) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 16)
*i = int16Value(v)
return err
}
func (i *int16Value) Type() string {
return "int16"
}
func (i *int16Value) String() string { return strconv.FormatInt(int64(*i), 10) }
func int16Conv(sval string) (interface{}, error) {
v, err := strconv.ParseInt(sval, 0, 16)
if err != nil {
return 0, err
}
return int16(v), nil
}
// GetInt16 returns the int16 value of a flag with the given name
func (f *FlagSet) GetInt16(name string) (int16, error) {
val, err := f.getFlagType(name, "int16", int16Conv)
if err != nil {
return 0, err
}
return val.(int16), nil
}
// Int16Var defines an int16 flag with specified name, default value, and usage string.
// The argument p points to an int16 variable in which to store the value of the flag.
func (f *FlagSet) Int16Var(p *int16, name string, value int16, usage string) {
f.VarP(newInt16Value(value, p), name, "", usage)
}
// Int16VarP is like Int16Var, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int16VarP(p *int16, name, shorthand string, value int16, usage string) {
f.VarP(newInt16Value(value, p), name, shorthand, usage)
}
// Int16Var defines an int16 flag with specified name, default value, and usage string.
// The argument p points to an int16 variable in which to store the value of the flag.
func Int16Var(p *int16, name string, value int16, usage string) {
CommandLine.VarP(newInt16Value(value, p), name, "", usage)
}
// Int16VarP is like Int16Var, but accepts a shorthand letter that can be used after a single dash.
func Int16VarP(p *int16, name, shorthand string, value int16, usage string) {
CommandLine.VarP(newInt16Value(value, p), name, shorthand, usage)
}
// Int16 defines an int16 flag with specified name, default value, and usage string.
// The return value is the address of an int16 variable that stores the value of the flag.
func (f *FlagSet) Int16(name string, value int16, usage string) *int16 {
p := new(int16)
f.Int16VarP(p, name, "", value, usage)
return p
}
// Int16P is like Int16, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) Int16P(name, shorthand string, value int16, usage string) *int16 {
p := new(int16)
f.Int16VarP(p, name, shorthand, value, usage)
return p
}
// Int16 defines an int16 flag with specified name, default value, and usage string.
// The return value is the address of an int16 variable that stores the value of the flag.
func Int16(name string, value int16, usage string) *int16 {
return CommandLine.Int16P(name, "", value, usage)
}
// Int16P is like Int16, but accepts a shorthand letter that can be used after a single dash.
func Int16P(name, shorthand string, value int16, usage string) *int16 {
return CommandLine.Int16P(name, shorthand, value, usage)
}

View file

@ -1,165 +0,0 @@
// Copyright 2009 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 pflag
import (
"fmt"
"strconv"
"strings"
"testing"
)
func setUpISFlagSet(isp *[]int) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.IntSliceVar(isp, "is", []int{}, "Command separated list!")
return f
}
func setUpISFlagSetWithDefault(isp *[]int) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.IntSliceVar(isp, "is", []int{0, 1}, "Command separated list!")
return f
}
func TestEmptyIS(t *testing.T) {
var is []int
f := setUpISFlagSet(&is)
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
getIS, err := f.GetIntSlice("is")
if err != nil {
t.Fatal("got an error from GetIntSlice():", err)
}
if len(getIS) != 0 {
t.Fatalf("got is %v with len=%d but expected length=0", getIS, len(getIS))
}
}
func TestIS(t *testing.T) {
var is []int
f := setUpISFlagSet(&is)
vals := []string{"1", "2", "4", "3"}
arg := fmt.Sprintf("--is=%s", strings.Join(vals, ","))
err := f.Parse([]string{arg})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range is {
d, err := strconv.Atoi(vals[i])
if err != nil {
t.Fatalf("got error: %v", err)
}
if d != v {
t.Fatalf("expected is[%d] to be %s but got: %d", i, vals[i], v)
}
}
getIS, err := f.GetIntSlice("is")
if err != nil {
t.Fatalf("got error: %v", err)
}
for i, v := range getIS {
d, err := strconv.Atoi(vals[i])
if err != nil {
t.Fatalf("got error: %v", err)
}
if d != v {
t.Fatalf("expected is[%d] to be %s but got: %d from GetIntSlice", i, vals[i], v)
}
}
}
func TestISDefault(t *testing.T) {
var is []int
f := setUpISFlagSetWithDefault(&is)
vals := []string{"0", "1"}
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range is {
d, err := strconv.Atoi(vals[i])
if err != nil {
t.Fatalf("got error: %v", err)
}
if d != v {
t.Fatalf("expected is[%d] to be %d but got: %d", i, d, v)
}
}
getIS, err := f.GetIntSlice("is")
if err != nil {
t.Fatal("got an error from GetIntSlice():", err)
}
for i, v := range getIS {
d, err := strconv.Atoi(vals[i])
if err != nil {
t.Fatal("got an error from GetIntSlice():", err)
}
if d != v {
t.Fatalf("expected is[%d] to be %d from GetIntSlice but got: %d", i, d, v)
}
}
}
func TestISWithDefault(t *testing.T) {
var is []int
f := setUpISFlagSetWithDefault(&is)
vals := []string{"1", "2"}
arg := fmt.Sprintf("--is=%s", strings.Join(vals, ","))
err := f.Parse([]string{arg})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range is {
d, err := strconv.Atoi(vals[i])
if err != nil {
t.Fatalf("got error: %v", err)
}
if d != v {
t.Fatalf("expected is[%d] to be %d but got: %d", i, d, v)
}
}
getIS, err := f.GetIntSlice("is")
if err != nil {
t.Fatal("got an error from GetIntSlice():", err)
}
for i, v := range getIS {
d, err := strconv.Atoi(vals[i])
if err != nil {
t.Fatalf("got error: %v", err)
}
if d != v {
t.Fatalf("expected is[%d] to be %d from GetIntSlice but got: %d", i, d, v)
}
}
}
func TestISCalledTwice(t *testing.T) {
var is []int
f := setUpISFlagSet(&is)
in := []string{"1,2", "3"}
expected := []int{1, 2, 3}
argfmt := "--is=%s"
arg1 := fmt.Sprintf(argfmt, in[0])
arg2 := fmt.Sprintf(argfmt, in[1])
err := f.Parse([]string{arg1, arg2})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range is {
if expected[i] != v {
t.Fatalf("expected is[%d] to be %d but got: %d", i, expected[i], v)
}
}
}

View file

@ -1,222 +0,0 @@
package pflag
import (
"fmt"
"net"
"strings"
"testing"
)
func setUpIPSFlagSet(ipsp *[]net.IP) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.IPSliceVar(ipsp, "ips", []net.IP{}, "Command separated list!")
return f
}
func setUpIPSFlagSetWithDefault(ipsp *[]net.IP) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.IPSliceVar(ipsp, "ips",
[]net.IP{
net.ParseIP("192.168.1.1"),
net.ParseIP("0:0:0:0:0:0:0:1"),
},
"Command separated list!")
return f
}
func TestEmptyIP(t *testing.T) {
var ips []net.IP
f := setUpIPSFlagSet(&ips)
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
getIPS, err := f.GetIPSlice("ips")
if err != nil {
t.Fatal("got an error from GetIPSlice():", err)
}
if len(getIPS) != 0 {
t.Fatalf("got ips %v with len=%d but expected length=0", getIPS, len(getIPS))
}
}
func TestIPS(t *testing.T) {
var ips []net.IP
f := setUpIPSFlagSet(&ips)
vals := []string{"192.168.1.1", "10.0.0.1", "0:0:0:0:0:0:0:2"}
arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ","))
err := f.Parse([]string{arg})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range ips {
if ip := net.ParseIP(vals[i]); ip == nil {
t.Fatalf("invalid string being converted to IP address: %s", vals[i])
} else if !ip.Equal(v) {
t.Fatalf("expected ips[%d] to be %s but got: %s from GetIPSlice", i, vals[i], v)
}
}
}
func TestIPSDefault(t *testing.T) {
var ips []net.IP
f := setUpIPSFlagSetWithDefault(&ips)
vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"}
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range ips {
if ip := net.ParseIP(vals[i]); ip == nil {
t.Fatalf("invalid string being converted to IP address: %s", vals[i])
} else if !ip.Equal(v) {
t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
}
}
getIPS, err := f.GetIPSlice("ips")
if err != nil {
t.Fatal("got an error from GetIPSlice")
}
for i, v := range getIPS {
if ip := net.ParseIP(vals[i]); ip == nil {
t.Fatalf("invalid string being converted to IP address: %s", vals[i])
} else if !ip.Equal(v) {
t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
}
}
}
func TestIPSWithDefault(t *testing.T) {
var ips []net.IP
f := setUpIPSFlagSetWithDefault(&ips)
vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"}
arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ","))
err := f.Parse([]string{arg})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range ips {
if ip := net.ParseIP(vals[i]); ip == nil {
t.Fatalf("invalid string being converted to IP address: %s", vals[i])
} else if !ip.Equal(v) {
t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
}
}
getIPS, err := f.GetIPSlice("ips")
if err != nil {
t.Fatal("got an error from GetIPSlice")
}
for i, v := range getIPS {
if ip := net.ParseIP(vals[i]); ip == nil {
t.Fatalf("invalid string being converted to IP address: %s", vals[i])
} else if !ip.Equal(v) {
t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
}
}
}
func TestIPSCalledTwice(t *testing.T) {
var ips []net.IP
f := setUpIPSFlagSet(&ips)
in := []string{"192.168.1.2,0:0:0:0:0:0:0:1", "10.0.0.1"}
expected := []net.IP{net.ParseIP("192.168.1.2"), net.ParseIP("0:0:0:0:0:0:0:1"), net.ParseIP("10.0.0.1")}
argfmt := "ips=%s"
arg1 := fmt.Sprintf(argfmt, in[0])
arg2 := fmt.Sprintf(argfmt, in[1])
err := f.Parse([]string{arg1, arg2})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range ips {
if !expected[i].Equal(v) {
t.Fatalf("expected ips[%d] to be %s but got: %s", i, expected[i], v)
}
}
}
func TestIPSBadQuoting(t *testing.T) {
tests := []struct {
Want []net.IP
FlagArg []string
}{
{
Want: []net.IP{
net.ParseIP("a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568"),
net.ParseIP("203.107.49.208"),
net.ParseIP("14.57.204.90"),
},
FlagArg: []string{
"a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568",
"203.107.49.208",
"14.57.204.90",
},
},
{
Want: []net.IP{
net.ParseIP("204.228.73.195"),
net.ParseIP("86.141.15.94"),
},
FlagArg: []string{
"204.228.73.195",
"86.141.15.94",
},
},
{
Want: []net.IP{
net.ParseIP("c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f"),
net.ParseIP("4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472"),
},
FlagArg: []string{
"c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f",
"4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472",
},
},
{
Want: []net.IP{
net.ParseIP("5170:f971:cfac:7be3:512a:af37:952c:bc33"),
net.ParseIP("93.21.145.140"),
net.ParseIP("2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca"),
},
FlagArg: []string{
" 5170:f971:cfac:7be3:512a:af37:952c:bc33 , 93.21.145.140 ",
"2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca",
},
},
{
Want: []net.IP{
net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
},
FlagArg: []string{
`"2e5e:66b2:6441:848:5b74:76ea:574c:3a7b, 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b,2e5e:66b2:6441:848:5b74:76ea:574c:3a7b "`,
" 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"},
},
}
for i, test := range tests {
var ips []net.IP
f := setUpIPSFlagSet(&ips)
if err := f.Parse([]string{fmt.Sprintf("--ips=%s", strings.Join(test.FlagArg, ","))}); err != nil {
t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%s",
err, test.FlagArg, test.Want[i])
}
for j, b := range ips {
if !b.Equal(test.Want[j]) {
t.Fatalf("bad value parsed for test %d on net.IP %d:\nwant:\t%s\ngot:\t%s", i, j, test.Want[j], b)
}
}
}
}

View file

@ -1,63 +0,0 @@
package pflag
import (
"fmt"
"net"
"os"
"testing"
)
func setUpIP(ip *net.IP) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.IPVar(ip, "address", net.ParseIP("0.0.0.0"), "IP Address")
return f
}
func TestIP(t *testing.T) {
testCases := []struct {
input string
success bool
expected string
}{
{"0.0.0.0", true, "0.0.0.0"},
{" 0.0.0.0 ", true, "0.0.0.0"},
{"1.2.3.4", true, "1.2.3.4"},
{"127.0.0.1", true, "127.0.0.1"},
{"255.255.255.255", true, "255.255.255.255"},
{"", false, ""},
{"0", false, ""},
{"localhost", false, ""},
{"0.0.0", false, ""},
{"0.0.0.", false, ""},
{"0.0.0.0.", false, ""},
{"0.0.0.256", false, ""},
{"0 . 0 . 0 . 0", false, ""},
}
devnull, _ := os.Open(os.DevNull)
os.Stderr = devnull
for i := range testCases {
var addr net.IP
f := setUpIP(&addr)
tc := &testCases[i]
arg := fmt.Sprintf("--address=%s", tc.input)
err := f.Parse([]string{arg})
if err != nil && tc.success == true {
t.Errorf("expected success, got %q", err)
continue
} else if err == nil && tc.success == false {
t.Errorf("expected failure")
continue
} else if tc.success {
ip, err := f.GetIP("address")
if err != nil {
t.Errorf("Got error trying to fetch the IP flag: %v", err)
}
if ip.String() != tc.expected {
t.Errorf("expected %q, got %q", tc.expected, ip.String())
}
}
}
}

View file

@ -1,70 +0,0 @@
package pflag
import (
"fmt"
"net"
"os"
"testing"
)
func setUpIPNet(ip *net.IPNet) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
_, def, _ := net.ParseCIDR("0.0.0.0/0")
f.IPNetVar(ip, "address", *def, "IP Address")
return f
}
func TestIPNet(t *testing.T) {
testCases := []struct {
input string
success bool
expected string
}{
{"0.0.0.0/0", true, "0.0.0.0/0"},
{" 0.0.0.0/0 ", true, "0.0.0.0/0"},
{"1.2.3.4/8", true, "1.0.0.0/8"},
{"127.0.0.1/16", true, "127.0.0.0/16"},
{"255.255.255.255/19", true, "255.255.224.0/19"},
{"255.255.255.255/32", true, "255.255.255.255/32"},
{"", false, ""},
{"/0", false, ""},
{"0", false, ""},
{"0/0", false, ""},
{"localhost/0", false, ""},
{"0.0.0/4", false, ""},
{"0.0.0./8", false, ""},
{"0.0.0.0./12", false, ""},
{"0.0.0.256/16", false, ""},
{"0.0.0.0 /20", false, ""},
{"0.0.0.0/ 24", false, ""},
{"0 . 0 . 0 . 0 / 28", false, ""},
{"0.0.0.0/33", false, ""},
}
devnull, _ := os.Open(os.DevNull)
os.Stderr = devnull
for i := range testCases {
var addr net.IPNet
f := setUpIPNet(&addr)
tc := &testCases[i]
arg := fmt.Sprintf("--address=%s", tc.input)
err := f.Parse([]string{arg})
if err != nil && tc.success == true {
t.Errorf("expected success, got %q", err)
continue
} else if err == nil && tc.success == false {
t.Errorf("expected failure")
continue
} else if tc.success {
ip, err := f.GetIPNet("address")
if err != nil {
t.Errorf("Got error trying to fetch the IP flag: %v", err)
}
if ip.String() != tc.expected {
t.Errorf("expected %q, got %q", tc.expected, ip.String())
}
}
}
}

View file

@ -52,7 +52,7 @@ func (f *FlagSet) GetStringArray(name string) ([]string, error) {
// StringArrayVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the values of the multiple flags.
// The value of each argument will not try to be separated by comma
// The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) {
f.VarP(newStringArrayValue(value, p), name, "", usage)
}
@ -64,7 +64,7 @@ func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []s
// StringArrayVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the value of the flag.
// The value of each argument will not try to be separated by comma
// The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func StringArrayVar(p *[]string, name string, value []string, usage string) {
CommandLine.VarP(newStringArrayValue(value, p), name, "", usage)
}
@ -76,7 +76,7 @@ func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage
// StringArray defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
// The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string {
p := []string{}
f.StringArrayVarP(&p, name, "", value, usage)
@ -92,7 +92,7 @@ func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage str
// StringArray defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
// The value of each argument will not try to be separated by comma. Use a StringSlice for that.
func StringArray(name string, value []string, usage string) *[]string {
return CommandLine.StringArrayP(name, "", value, usage)
}

View file

@ -1,233 +0,0 @@
// Copyright 2009 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 pflag
import (
"fmt"
"testing"
)
func setUpSAFlagSet(sap *[]string) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.StringArrayVar(sap, "sa", []string{}, "Command separated list!")
return f
}
func setUpSAFlagSetWithDefault(sap *[]string) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.StringArrayVar(sap, "sa", []string{"default", "values"}, "Command separated list!")
return f
}
func TestEmptySA(t *testing.T) {
var sa []string
f := setUpSAFlagSet(&sa)
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
getSA, err := f.GetStringArray("sa")
if err != nil {
t.Fatal("got an error from GetStringArray():", err)
}
if len(getSA) != 0 {
t.Fatalf("got sa %v with len=%d but expected length=0", getSA, len(getSA))
}
}
func TestEmptySAValue(t *testing.T) {
var sa []string
f := setUpSAFlagSet(&sa)
err := f.Parse([]string{"--sa="})
if err != nil {
t.Fatal("expected no error; got", err)
}
getSA, err := f.GetStringArray("sa")
if err != nil {
t.Fatal("got an error from GetStringArray():", err)
}
if len(getSA) != 0 {
t.Fatalf("got sa %v with len=%d but expected length=0", getSA, len(getSA))
}
}
func TestSADefault(t *testing.T) {
var sa []string
f := setUpSAFlagSetWithDefault(&sa)
vals := []string{"default", "values"}
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range sa {
if vals[i] != v {
t.Fatalf("expected sa[%d] to be %s but got: %s", i, vals[i], v)
}
}
getSA, err := f.GetStringArray("sa")
if err != nil {
t.Fatal("got an error from GetStringArray():", err)
}
for i, v := range getSA {
if vals[i] != v {
t.Fatalf("expected sa[%d] to be %s from GetStringArray but got: %s", i, vals[i], v)
}
}
}
func TestSAWithDefault(t *testing.T) {
var sa []string
f := setUpSAFlagSetWithDefault(&sa)
val := "one"
arg := fmt.Sprintf("--sa=%s", val)
err := f.Parse([]string{arg})
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(sa) != 1 {
t.Fatalf("expected number of values to be %d but %d", 1, len(sa))
}
if sa[0] != val {
t.Fatalf("expected value to be %s but got: %s", sa[0], val)
}
getSA, err := f.GetStringArray("sa")
if err != nil {
t.Fatal("got an error from GetStringArray():", err)
}
if len(getSA) != 1 {
t.Fatalf("expected number of values to be %d but %d", 1, len(getSA))
}
if getSA[0] != val {
t.Fatalf("expected value to be %s but got: %s", getSA[0], val)
}
}
func TestSACalledTwice(t *testing.T) {
var sa []string
f := setUpSAFlagSet(&sa)
in := []string{"one", "two"}
expected := []string{"one", "two"}
argfmt := "--sa=%s"
arg1 := fmt.Sprintf(argfmt, in[0])
arg2 := fmt.Sprintf(argfmt, in[1])
err := f.Parse([]string{arg1, arg2})
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(sa) {
t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa))
}
for i, v := range sa {
if expected[i] != v {
t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v)
}
}
values, err := f.GetStringArray("sa")
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(values) {
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(sa))
}
for i, v := range values {
if expected[i] != v {
t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v)
}
}
}
func TestSAWithSpecialChar(t *testing.T) {
var sa []string
f := setUpSAFlagSet(&sa)
in := []string{"one,two", `"three"`, `"four,five",six`, "seven eight"}
expected := []string{"one,two", `"three"`, `"four,five",six`, "seven eight"}
argfmt := "--sa=%s"
arg1 := fmt.Sprintf(argfmt, in[0])
arg2 := fmt.Sprintf(argfmt, in[1])
arg3 := fmt.Sprintf(argfmt, in[2])
arg4 := fmt.Sprintf(argfmt, in[3])
err := f.Parse([]string{arg1, arg2, arg3, arg4})
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(sa) {
t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa))
}
for i, v := range sa {
if expected[i] != v {
t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v)
}
}
values, err := f.GetStringArray("sa")
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(values) {
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values))
}
for i, v := range values {
if expected[i] != v {
t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v)
}
}
}
func TestSAWithSquareBrackets(t *testing.T) {
var sa []string
f := setUpSAFlagSet(&sa)
in := []string{"][]-[", "[a-z]", "[a-z]+"}
expected := []string{"][]-[", "[a-z]", "[a-z]+"}
argfmt := "--sa=%s"
arg1 := fmt.Sprintf(argfmt, in[0])
arg2 := fmt.Sprintf(argfmt, in[1])
arg3 := fmt.Sprintf(argfmt, in[2])
err := f.Parse([]string{arg1, arg2, arg3})
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(sa) {
t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa))
}
for i, v := range sa {
if expected[i] != v {
t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v)
}
}
values, err := f.GetStringArray("sa")
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(values) {
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values))
}
for i, v := range values {
if expected[i] != v {
t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v)
}
}
}

View file

@ -82,6 +82,11 @@ func (f *FlagSet) GetStringSlice(name string) ([]string, error) {
// StringSliceVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) {
f.VarP(newStringSliceValue(value, p), name, "", usage)
}
@ -93,6 +98,11 @@ func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []s
// StringSliceVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func StringSliceVar(p *[]string, name string, value []string, usage string) {
CommandLine.VarP(newStringSliceValue(value, p), name, "", usage)
}
@ -104,6 +114,11 @@ func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage
// StringSlice defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string {
p := []string{}
f.StringSliceVarP(&p, name, "", value, usage)
@ -119,6 +134,11 @@ func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage str
// StringSlice defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
// --ss="v1,v2" -ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func StringSlice(name string, value []string, usage string) *[]string {
return CommandLine.StringSliceP(name, "", value, usage)
}

View file

@ -1,253 +0,0 @@
// Copyright 2009 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 pflag
import (
"fmt"
"strings"
"testing"
)
func setUpSSFlagSet(ssp *[]string) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.StringSliceVar(ssp, "ss", []string{}, "Command separated list!")
return f
}
func setUpSSFlagSetWithDefault(ssp *[]string) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.StringSliceVar(ssp, "ss", []string{"default", "values"}, "Command separated list!")
return f
}
func TestEmptySS(t *testing.T) {
var ss []string
f := setUpSSFlagSet(&ss)
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
getSS, err := f.GetStringSlice("ss")
if err != nil {
t.Fatal("got an error from GetStringSlice():", err)
}
if len(getSS) != 0 {
t.Fatalf("got ss %v with len=%d but expected length=0", getSS, len(getSS))
}
}
func TestEmptySSValue(t *testing.T) {
var ss []string
f := setUpSSFlagSet(&ss)
err := f.Parse([]string{"--ss="})
if err != nil {
t.Fatal("expected no error; got", err)
}
getSS, err := f.GetStringSlice("ss")
if err != nil {
t.Fatal("got an error from GetStringSlice():", err)
}
if len(getSS) != 0 {
t.Fatalf("got ss %v with len=%d but expected length=0", getSS, len(getSS))
}
}
func TestSS(t *testing.T) {
var ss []string
f := setUpSSFlagSet(&ss)
vals := []string{"one", "two", "4", "3"}
arg := fmt.Sprintf("--ss=%s", strings.Join(vals, ","))
err := f.Parse([]string{arg})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range ss {
if vals[i] != v {
t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v)
}
}
getSS, err := f.GetStringSlice("ss")
if err != nil {
t.Fatal("got an error from GetStringSlice():", err)
}
for i, v := range getSS {
if vals[i] != v {
t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v)
}
}
}
func TestSSDefault(t *testing.T) {
var ss []string
f := setUpSSFlagSetWithDefault(&ss)
vals := []string{"default", "values"}
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range ss {
if vals[i] != v {
t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v)
}
}
getSS, err := f.GetStringSlice("ss")
if err != nil {
t.Fatal("got an error from GetStringSlice():", err)
}
for i, v := range getSS {
if vals[i] != v {
t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v)
}
}
}
func TestSSWithDefault(t *testing.T) {
var ss []string
f := setUpSSFlagSetWithDefault(&ss)
vals := []string{"one", "two", "4", "3"}
arg := fmt.Sprintf("--ss=%s", strings.Join(vals, ","))
err := f.Parse([]string{arg})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range ss {
if vals[i] != v {
t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v)
}
}
getSS, err := f.GetStringSlice("ss")
if err != nil {
t.Fatal("got an error from GetStringSlice():", err)
}
for i, v := range getSS {
if vals[i] != v {
t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v)
}
}
}
func TestSSCalledTwice(t *testing.T) {
var ss []string
f := setUpSSFlagSet(&ss)
in := []string{"one,two", "three"}
expected := []string{"one", "two", "three"}
argfmt := "--ss=%s"
arg1 := fmt.Sprintf(argfmt, in[0])
arg2 := fmt.Sprintf(argfmt, in[1])
err := f.Parse([]string{arg1, arg2})
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(ss) {
t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss))
}
for i, v := range ss {
if expected[i] != v {
t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v)
}
}
values, err := f.GetStringSlice("ss")
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(values) {
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(ss))
}
for i, v := range values {
if expected[i] != v {
t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v)
}
}
}
func TestSSWithComma(t *testing.T) {
var ss []string
f := setUpSSFlagSet(&ss)
in := []string{`"one,two"`, `"three"`, `"four,five",six`}
expected := []string{"one,two", "three", "four,five", "six"}
argfmt := "--ss=%s"
arg1 := fmt.Sprintf(argfmt, in[0])
arg2 := fmt.Sprintf(argfmt, in[1])
arg3 := fmt.Sprintf(argfmt, in[2])
err := f.Parse([]string{arg1, arg2, arg3})
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(ss) {
t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss))
}
for i, v := range ss {
if expected[i] != v {
t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v)
}
}
values, err := f.GetStringSlice("ss")
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(values) {
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values))
}
for i, v := range values {
if expected[i] != v {
t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v)
}
}
}
func TestSSWithSquareBrackets(t *testing.T) {
var ss []string
f := setUpSSFlagSet(&ss)
in := []string{`"[a-z]"`, `"[a-z]+"`}
expected := []string{"[a-z]", "[a-z]+"}
argfmt := "--ss=%s"
arg1 := fmt.Sprintf(argfmt, in[0])
arg2 := fmt.Sprintf(argfmt, in[1])
err := f.Parse([]string{arg1, arg2})
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(ss) {
t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss))
}
for i, v := range ss {
if expected[i] != v {
t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v)
}
}
values, err := f.GetStringSlice("ss")
if err != nil {
t.Fatal("expected no error; got", err)
}
if len(expected) != len(values) {
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values))
}
for i, v := range values {
if expected[i] != v {
t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v)
}
}
}

View file

@ -1,161 +0,0 @@
package pflag
import (
"fmt"
"strconv"
"strings"
"testing"
)
func setUpUISFlagSet(uisp *[]uint) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.UintSliceVar(uisp, "uis", []uint{}, "Command separated list!")
return f
}
func setUpUISFlagSetWithDefault(uisp *[]uint) *FlagSet {
f := NewFlagSet("test", ContinueOnError)
f.UintSliceVar(uisp, "uis", []uint{0, 1}, "Command separated list!")
return f
}
func TestEmptyUIS(t *testing.T) {
var uis []uint
f := setUpUISFlagSet(&uis)
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
getUIS, err := f.GetUintSlice("uis")
if err != nil {
t.Fatal("got an error from GetUintSlice():", err)
}
if len(getUIS) != 0 {
t.Fatalf("got is %v with len=%d but expected length=0", getUIS, len(getUIS))
}
}
func TestUIS(t *testing.T) {
var uis []uint
f := setUpUISFlagSet(&uis)
vals := []string{"1", "2", "4", "3"}
arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ","))
err := f.Parse([]string{arg})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range uis {
u, err := strconv.ParseUint(vals[i], 10, 0)
if err != nil {
t.Fatalf("got error: %v", err)
}
if uint(u) != v {
t.Fatalf("expected uis[%d] to be %s but got %d", i, vals[i], v)
}
}
getUIS, err := f.GetUintSlice("uis")
if err != nil {
t.Fatalf("got error: %v", err)
}
for i, v := range getUIS {
u, err := strconv.ParseUint(vals[i], 10, 0)
if err != nil {
t.Fatalf("got error: %v", err)
}
if uint(u) != v {
t.Fatalf("expected uis[%d] to be %s but got: %d from GetUintSlice", i, vals[i], v)
}
}
}
func TestUISDefault(t *testing.T) {
var uis []uint
f := setUpUISFlagSetWithDefault(&uis)
vals := []string{"0", "1"}
err := f.Parse([]string{})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range uis {
u, err := strconv.ParseUint(vals[i], 10, 0)
if err != nil {
t.Fatalf("got error: %v", err)
}
if uint(u) != v {
t.Fatalf("expect uis[%d] to be %d but got: %d", i, u, v)
}
}
getUIS, err := f.GetUintSlice("uis")
if err != nil {
t.Fatal("got an error from GetUintSlice():", err)
}
for i, v := range getUIS {
u, err := strconv.ParseUint(vals[i], 10, 0)
if err != nil {
t.Fatal("got an error from GetIntSlice():", err)
}
if uint(u) != v {
t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v)
}
}
}
func TestUISWithDefault(t *testing.T) {
var uis []uint
f := setUpUISFlagSetWithDefault(&uis)
vals := []string{"1", "2"}
arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ","))
err := f.Parse([]string{arg})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range uis {
u, err := strconv.ParseUint(vals[i], 10, 0)
if err != nil {
t.Fatalf("got error: %v", err)
}
if uint(u) != v {
t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v)
}
}
getUIS, err := f.GetUintSlice("uis")
if err != nil {
t.Fatal("got an error from GetUintSlice():", err)
}
for i, v := range getUIS {
u, err := strconv.ParseUint(vals[i], 10, 0)
if err != nil {
t.Fatalf("got error: %v", err)
}
if uint(u) != v {
t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v)
}
}
}
func TestUISCalledTwice(t *testing.T) {
var uis []uint
f := setUpUISFlagSet(&uis)
in := []string{"1,2", "3"}
expected := []int{1, 2, 3}
argfmt := "--uis=%s"
arg1 := fmt.Sprintf(argfmt, in[0])
arg2 := fmt.Sprintf(argfmt, in[1])
err := f.Parse([]string{arg1, arg2})
if err != nil {
t.Fatal("expected no error; got", err)
}
for i, v := range uis {
if uint(expected[i]) != v {
t.Fatalf("expected uis[%d] to be %d but got: %d", i, expected[i], v)
}
}
}