Skip to content

Commit

Permalink
[WIP] Refactor filename - file relation
Browse files Browse the repository at this point in the history
  • Loading branch information
magik6k committed Oct 23, 2018
1 parent 90d206a commit 6c67781
Show file tree
Hide file tree
Showing 12 changed files with 325 additions and 231 deletions.
56 changes: 23 additions & 33 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,46 @@ import (
)

var (
ErrNotDirectory = errors.New("Couldn't call NextFile(), this isn't a directory")
ErrNotReader = errors.New("This file is a directory, can't use Reader functions")
ErrNotDirectory = errors.New("couldn't call NextFile(), this isn't a directory")
ErrNotReader = errors.New("this file is a directory, can't use Reader functions")

ErrNotSupported = errors.New("operation not supported")
)

// File is an interface that provides functionality for handling
// files/directories as values that can be supplied to commands. For
// directories, child files are accessed serially by calling `NextFile()`.
// directories, child files are accessed serially by calling `Files()`
// or `Walk()`.
//
// Read/Seek/Close methods are only valid for files
// Files/Walk methods are only valid for directories
type File interface {
// Files implement ReadCloser, but can only be read from or closed if
// they are not directories
io.ReadCloser

// FileName returns a filename associated with this file
FileName() string
io.Reader
io.Closer
io.Seeker

// FullPath returns the full path used when adding with this file
FullPath() string
// Size returns size of the
Size() (int64, error)

// IsDirectory returns true if the File is a directory (and therefore
// supports calling `NextFile`) and false if the File is a normal file
// (and therefor supports calling `Read` and `Close`)
// supports calling `Files`/`Walk`) and false if the File is a normal file
// (and therefore supports calling `Read`/`Close`/`Seek`)
IsDirectory() bool

// NextFile returns the next child file available (if the File is a
// directory). It will return (nil, io.EOF) if no more files are
// directory). It will return io.EOF if no more files are
// available. If the file is a regular file (not a directory), NextFile
// will return a non-nil error.
NextFile() (File, error)
NextFile() (string, File, error)
}

type StatFile interface {
File

Stat() os.FileInfo
}

type PeekFile interface {
SizeFile

Peek(n int) File
Length() int
}

type SizeFile interface {
// FileInfo exposes information on files in local filesystem
type FileInfo interface {
File

Size() (int64, error)
}

type FileInfo interface {
// AbsPath returns full/real file path.
AbsPath() string

// Stat returns os.Stat of this file
Stat() os.FileInfo
}
43 changes: 21 additions & 22 deletions file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ import (
)

func TestSliceFiles(t *testing.T) {
name := "testname"
files := []File{
NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader("Some text!\n")), nil),
NewReaderFile("beep.txt", "beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil),
NewReaderFile("boop.txt", "boop.txt", ioutil.NopCloser(strings.NewReader("boop")), nil),
files := []FileEntry{
{NewReaderFile(ioutil.NopCloser(strings.NewReader("Some text!\n")), nil), ""},
{NewReaderFile(ioutil.NopCloser(strings.NewReader("beep")), nil), ""},
{NewReaderFile(ioutil.NopCloser(strings.NewReader("boop")), nil), ""},
}
buf := make([]byte, 20)

sf := NewSliceFile(name, name, files)
sf := NewSliceFile(files)

if !sf.IsDirectory() {
t.Fatal("SliceFile should always be a directory")
Expand All @@ -31,7 +30,7 @@ func TestSliceFiles(t *testing.T) {
t.Fatal("Shouldn't be able to call `Close` on a SliceFile")
}

file, err := sf.NextFile()
_, file, err := sf.NextFile()
if file == nil || err != nil {
t.Fatal("Expected a file and nil error")
}
Expand All @@ -40,30 +39,30 @@ func TestSliceFiles(t *testing.T) {
t.Fatal("NextFile got a file in the wrong order")
}

file, err = sf.NextFile()
_, file, err = sf.NextFile()
if file == nil || err != nil {
t.Fatal("Expected a file and nil error")
}
file, err = sf.NextFile()
_, file, err = sf.NextFile()
if file == nil || err != nil {
t.Fatal("Expected a file and nil error")
}

file, err = sf.NextFile()
_, file, err = sf.NextFile()
if file != nil || err != io.EOF {
t.Fatal("Expected a nil file and io.EOF")
}
}

func TestReaderFiles(t *testing.T) {
message := "beep boop"
rf := NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader(message)), nil)
rf := NewReaderFile(ioutil.NopCloser(strings.NewReader(message)), nil)
buf := make([]byte, len(message))

if rf.IsDirectory() {
t.Fatal("ReaderFile should never be a directory")
}
file, err := rf.NextFile()
_, file, err := rf.NextFile()
if file != nil || err != ErrNotDirectory {
t.Fatal("Expected a nil file and ErrNotDirectory")
}
Expand Down Expand Up @@ -114,17 +113,17 @@ anotherfile
if part == nil || err != nil {
t.Fatal("Expected non-nil part, nil error")
}
mpf, err := NewFileFromPart(part)
mpname, mpf, err := newFileFromPart("", part, mpReader)
if mpf == nil || err != nil {
t.Fatal("Expected non-nil MultipartFile, nil error")
}
if mpf.IsDirectory() {
t.Fatal("Expected file to not be a directory")
}
if mpf.FileName() != "name" {
if mpname != "name" {
t.Fatal("Expected filename to be \"name\"")
}
if file, err := mpf.NextFile(); file != nil || err != ErrNotDirectory {
if _, file, err := mpf.NextFile(); file != nil || err != ErrNotDirectory {
t.Fatal("Expected a nil file and ErrNotDirectory")
}
if n, err := mpf.Read(buf); n != 4 || !(err == io.EOF || err == nil) {
Expand All @@ -139,14 +138,14 @@ anotherfile
if part == nil || err != nil {
t.Fatal("Expected non-nil part, nil error")
}
mpf, err = NewFileFromPart(part)
mpname, mpf, err = newFileFromPart("", part, mpReader)
if mpf == nil || err != nil {
t.Fatal("Expected non-nil MultipartFile, nil error")
}
if !mpf.IsDirectory() {
t.Fatal("Expected file to be a directory")
}
if mpf.FileName() != "dir" {
if mpname != "dir" {
t.Fatal("Expected filename to be \"dir\"")
}
if n, err := mpf.Read(buf); n > 0 || err != ErrNotReader {
Expand All @@ -161,15 +160,15 @@ anotherfile
if part == nil || err != nil {
t.Fatal("Expected non-nil part, nil error")
}
mpf, err = NewFileFromPart(part)
mpname, mpf, err = newFileFromPart("dir/", part, mpReader)
if mpf == nil || err != nil {
t.Fatal("Expected non-nil MultipartFile, nil error")
}
if mpf.IsDirectory() {
t.Fatal("Expected file, got directory")
}
if mpf.FileName() != "dir/nested" {
t.Fatalf("Expected filename to be \"nested\", got %s", mpf.FileName())
if mpname != "nested" {
t.Fatalf("Expected filename to be \"nested\", got %s", mpname)
}
if n, err := mpf.Read(buf); n != 12 || !(err == nil || err == io.EOF) {
t.Fatalf("expected to be able to read 12 bytes from file: %s (got %d)", err, n)
Expand All @@ -183,14 +182,14 @@ anotherfile
if part == nil || err != nil {
t.Fatal("Expected non-nil part, nil error")
}
mpf, err = NewFileFromPart(part)
mpname, mpf, err = newFileFromPart("dir/", part, mpReader)
if mpf == nil || err != nil {
t.Fatal("Expected non-nil MultipartFile, nil error")
}
if mpf.IsDirectory() {
t.Fatal("Expected file to be a symlink")
}
if mpf.FileName() != "dir/simlynk" {
if mpname != "simlynk" {
t.Fatal("Expected filename to be \"dir/simlynk\"")
}
slink, ok := mpf.(*Symlink)
Expand Down
5 changes: 2 additions & 3 deletions is_hidden.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import (
"strings"
)

func IsHidden(f File) bool {

fName := filepath.Base(f.FileName())
func IsHidden(name string, f File) bool {
fName := filepath.Base(name)

if strings.HasPrefix(fName, ".") && len(fName) > 1 {
return true
Expand Down
9 changes: 7 additions & 2 deletions is_hidden_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@ import (
windows "golang.org/x/sys/windows"
)

func IsHidden(f File) bool {
func IsHidden(name string, f File) bool {

fName := filepath.Base(f.FileName())

if strings.HasPrefix(fName, ".") && len(fName) > 1 {
return true
}

p, e := windows.UTF16PtrFromString(f.FullPath())
fi, ok := f.(FileInfo)
if !ok {
return false
}

p, e := windows.UTF16PtrFromString(fi.AbsPath())
if e != nil {
return false
}
Expand Down
32 changes: 19 additions & 13 deletions linkfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ import (
)

type Symlink struct {
name string
path string
Target string
stat os.FileInfo

reader io.Reader
}

func NewLinkFile(name, path, target string, stat os.FileInfo) File {
func NewLinkFile(path, target string, stat os.FileInfo) File {
return &Symlink{
name: name,
path: path,
Target: target,
stat: stat,
Expand All @@ -29,22 +27,30 @@ func (lf *Symlink) IsDirectory() bool {
return false
}

func (lf *Symlink) NextFile() (File, error) {
return nil, io.EOF
func (lf *Symlink) NextFile() (string, File, error) {
return "", nil, ErrNotDirectory
}

func (f *Symlink) FileName() string {
return f.name
}
func (lf *Symlink) Close() error {
if c, ok := lf.reader.(io.Closer); ok {
return c.Close()
}

func (f *Symlink) Close() error {
return nil
}

func (f *Symlink) FullPath() string {
return f.path
func (lf *Symlink) Read(b []byte) (int, error) {
return lf.reader.Read(b)
}

func (lf *Symlink) Seek(offset int64, whence int) (int64, error) {
if s, ok := lf.reader.(io.Seeker); ok {
return s.Seek(offset, whence)
}

return 0, ErrNotSupported
}

func (f *Symlink) Read(b []byte) (int, error) {
return f.reader.Read(b)
func (lf *Symlink) Size() (int64, error) {
return 0, ErrNotSupported
}
Loading

0 comments on commit 6c67781

Please sign in to comment.