diff --git a/.gx/lastpubver b/.gx/lastpubver index 19f49f9..a7af607 100644 --- a/.gx/lastpubver +++ b/.gx/lastpubver @@ -1 +1 @@ -1.1.3: QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky +1.2.0: Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg diff --git a/files/file.go b/files/file.go deleted file mode 100644 index c5e8203..0000000 --- a/files/file.go +++ /dev/null @@ -1,62 +0,0 @@ -package files - -import ( - "errors" - "io" - "os" -) - -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") -) - -// 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()`. -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 - - // FullPath returns the full path used when adding with this file - FullPath() string - - // 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`) - 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 - // available. If the file is a regular file (not a directory), NextFile - // will return a non-nil error. - NextFile() (File, error) -} - -type StatFile interface { - File - - Stat() os.FileInfo -} - -type PeekFile interface { - SizeFile - - Peek(n int) File - Length() int -} - -type SizeFile interface { - File - - Size() (int64, error) -} - -type FileInfo interface { - AbsPath() string - Stat() os.FileInfo -} diff --git a/files/file_test.go b/files/file_test.go deleted file mode 100644 index 733a8c8..0000000 --- a/files/file_test.go +++ /dev/null @@ -1,203 +0,0 @@ -package files - -import ( - "io" - "io/ioutil" - "mime/multipart" - "strings" - "testing" -) - -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), - } - buf := make([]byte, 20) - - sf := NewSliceFile(name, name, files) - - if !sf.IsDirectory() { - t.Fatal("SliceFile should always be a directory") - } - - if n, err := sf.Read(buf); n > 0 || err != io.EOF { - t.Fatal("Shouldn't be able to read data from a SliceFile") - } - - if err := sf.Close(); err != ErrNotReader { - t.Fatal("Shouldn't be able to call `Close` on a SliceFile") - } - - file, err := sf.NextFile() - if file == nil || err != nil { - t.Fatal("Expected a file and nil error") - } - read, err := file.Read(buf) - if read != 11 || err != nil { - t.Fatal("NextFile got a file in the wrong order") - } - - file, err = sf.NextFile() - if file == nil || err != nil { - t.Fatal("Expected a file and nil error") - } - file, err = sf.NextFile() - if file == nil || err != nil { - t.Fatal("Expected a file and nil error") - } - - 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) - buf := make([]byte, len(message)) - - if rf.IsDirectory() { - t.Fatal("ReaderFile should never be a directory") - } - file, err := rf.NextFile() - if file != nil || err != ErrNotDirectory { - t.Fatal("Expected a nil file and ErrNotDirectory") - } - - if n, err := rf.Read(buf); n == 0 || err != nil { - t.Fatal("Expected to be able to read") - } - if err := rf.Close(); err != nil { - t.Fatal("Should be able to close") - } - if n, err := rf.Read(buf); n != 0 || err != io.EOF { - t.Fatal("Expected EOF when reading after close") - } -} - -func TestMultipartFiles(t *testing.T) { - data := ` ---Boundary! -Content-Type: text/plain -Content-Disposition: file; filename="name" -Some-Header: beep - -beep ---Boundary! -Content-Type: application/x-directory -Content-Disposition: file; filename="dir" - ---Boundary! -Content-Type: text/plain -Content-Disposition: file; filename="dir/nested" - -some content ---Boundary! -Content-Type: application/symlink -Content-Disposition: file; filename="dir/simlynk" - -anotherfile ---Boundary!-- - -` - - reader := strings.NewReader(data) - mpReader := multipart.NewReader(reader, "Boundary!") - buf := make([]byte, 20) - - // test properties of a file created from the first part - part, err := mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - mpf, err := NewFileFromPart(part) - 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" { - t.Fatal("Expected filename to be \"name\"") - } - 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) { - t.Fatal("Expected to be able to read 4 bytes", n, err) - } - if err := mpf.Close(); err != nil { - t.Fatal("Expected to be able to close file") - } - - // test properties of file created from second part (directory) - part, err = mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - mpf, err = NewFileFromPart(part) - 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" { - t.Fatal("Expected filename to be \"dir\"") - } - if n, err := mpf.Read(buf); n > 0 || err != ErrNotReader { - t.Fatal("Shouldn't be able to call `Read` on a directory") - } - if err := mpf.Close(); err != ErrNotReader { - t.Fatal("Shouldn't be able to call `Close` on a directory") - } - - // test properties of file created from third part (nested file) - part, err = mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - mpf, err = NewFileFromPart(part) - 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 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) - } - if err := mpf.Close(); err != nil { - t.Fatalf("should be able to close file: %s", err) - } - - // test properties of symlink created from fourth part (symlink) - part, err = mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - mpf, err = NewFileFromPart(part) - 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" { - t.Fatal("Expected filename to be \"dir/simlynk\"") - } - slink, ok := mpf.(*Symlink) - if !ok { - t.Fatalf("expected file to be a symlink") - } - if slink.Target != "anotherfile" { - t.Fatal("expected link to point to anotherfile") - } -} diff --git a/files/is_hidden.go b/files/is_hidden.go deleted file mode 100644 index b036068..0000000 --- a/files/is_hidden.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build !windows - -package files - -import ( - "path/filepath" - "strings" -) - -func IsHidden(f File) bool { - - fName := filepath.Base(f.FileName()) - - if strings.HasPrefix(fName, ".") && len(fName) > 1 { - return true - } - - return false -} diff --git a/files/is_hidden_windows.go b/files/is_hidden_windows.go deleted file mode 100644 index 7679433..0000000 --- a/files/is_hidden_windows.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build windows - -package files - -import ( - "path/filepath" - "strings" - - windows "golang.org/x/sys/windows" -) - -func IsHidden(f File) bool { - - fName := filepath.Base(f.FileName()) - - if strings.HasPrefix(fName, ".") && len(fName) > 1 { - return true - } - - p, e := windows.UTF16PtrFromString(f.FullPath()) - if e != nil { - return false - } - - attrs, e := windows.GetFileAttributes(p) - if e != nil { - return false - } - return attrs&windows.FILE_ATTRIBUTE_HIDDEN != 0 -} diff --git a/files/linkfile.go b/files/linkfile.go deleted file mode 100644 index 18466f4..0000000 --- a/files/linkfile.go +++ /dev/null @@ -1,50 +0,0 @@ -package files - -import ( - "io" - "os" - "strings" -) - -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 { - return &Symlink{ - name: name, - path: path, - Target: target, - stat: stat, - reader: strings.NewReader(target), - } -} - -func (lf *Symlink) IsDirectory() bool { - return false -} - -func (lf *Symlink) NextFile() (File, error) { - return nil, io.EOF -} - -func (f *Symlink) FileName() string { - return f.name -} - -func (f *Symlink) Close() error { - return nil -} - -func (f *Symlink) FullPath() string { - return f.path -} - -func (f *Symlink) Read(b []byte) (int, error) { - return f.reader.Read(b) -} diff --git a/files/multifilereader.go b/files/multifilereader.go deleted file mode 100644 index 4833e8d..0000000 --- a/files/multifilereader.go +++ /dev/null @@ -1,124 +0,0 @@ -package files - -import ( - "bytes" - "fmt" - "io" - "mime/multipart" - "net/textproto" - "net/url" - "sync" -) - -// MultiFileReader reads from a `commands.File` (which can be a directory of files -// or a regular file) as HTTP multipart encoded data. -type MultiFileReader struct { - io.Reader - - files []File - currentFile io.Reader - buf bytes.Buffer - mpWriter *multipart.Writer - closed bool - mutex *sync.Mutex - - // if true, the data will be type 'multipart/form-data' - // if false, the data will be type 'multipart/mixed' - form bool -} - -// NewMultiFileReader constructs a MultiFileReader. `file` can be any `commands.File`. -// If `form` is set to true, the multipart data will have a Content-Type of 'multipart/form-data', -// if `form` is false, the Content-Type will be 'multipart/mixed'. -func NewMultiFileReader(file File, form bool) *MultiFileReader { - mfr := &MultiFileReader{ - files: []File{file}, - form: form, - mutex: &sync.Mutex{}, - } - mfr.mpWriter = multipart.NewWriter(&mfr.buf) - - return mfr -} - -func (mfr *MultiFileReader) Read(buf []byte) (written int, err error) { - mfr.mutex.Lock() - defer mfr.mutex.Unlock() - - // if we are closed and the buffer is flushed, end reading - if mfr.closed && mfr.buf.Len() == 0 { - return 0, io.EOF - } - - // if the current file isn't set, advance to the next file - if mfr.currentFile == nil { - var file File - for file == nil { - if len(mfr.files) == 0 { - mfr.mpWriter.Close() - mfr.closed = true - return mfr.buf.Read(buf) - } - - nextfile, err := mfr.files[len(mfr.files)-1].NextFile() - if err == io.EOF { - mfr.files = mfr.files[:len(mfr.files)-1] - continue - } else if err != nil { - return 0, err - } - - file = nextfile - } - - // handle starting a new file part - if !mfr.closed { - - var contentType string - if _, ok := file.(*Symlink); ok { - contentType = "application/symlink" - } else if file.IsDirectory() { - mfr.files = append(mfr.files, file) - contentType = "application/x-directory" - } else { - // otherwise, use the file as a reader to read its contents - contentType = "application/octet-stream" - } - - mfr.currentFile = file - - // write the boundary and headers - header := make(textproto.MIMEHeader) - filename := url.QueryEscape(file.FileName()) - header.Set("Content-Disposition", fmt.Sprintf("file; filename=\"%s\"", filename)) - - header.Set("Content-Type", contentType) - if rf, ok := file.(*ReaderFile); ok { - header.Set("abspath", rf.AbsPath()) - } - - _, err := mfr.mpWriter.CreatePart(header) - if err != nil { - return 0, err - } - } - } - - // if the buffer has something in it, read from it - if mfr.buf.Len() > 0 { - return mfr.buf.Read(buf) - } - - // otherwise, read from file data - written, err = mfr.currentFile.Read(buf) - if err == io.EOF { - mfr.currentFile = nil - return written, nil - } - return written, err -} - -// Boundary returns the boundary string to be used to separate files in the multipart data -func (mfr *MultiFileReader) Boundary() string { - return mfr.mpWriter.Boundary() -} diff --git a/files/multifilereader_test.go b/files/multifilereader_test.go deleted file mode 100644 index 3d2c978..0000000 --- a/files/multifilereader_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package files - -import ( - "io" - "io/ioutil" - "mime/multipart" - "strings" - "testing" -) - -func TestOutput(t *testing.T) { - text := "Some text! :)" - fileset := []File{ - NewReaderFile("file.txt", "file.txt", ioutil.NopCloser(strings.NewReader(text)), nil), - NewSliceFile("boop", "boop", []File{ - NewReaderFile("boop/a.txt", "boop/a.txt", ioutil.NopCloser(strings.NewReader("bleep")), nil), - NewReaderFile("boop/b.txt", "boop/b.txt", ioutil.NopCloser(strings.NewReader("bloop")), nil), - }), - NewReaderFile("beep.txt", "beep.txt", ioutil.NopCloser(strings.NewReader("beep")), nil), - } - sf := NewSliceFile("", "", fileset) - buf := make([]byte, 20) - - // testing output by reading it with the go stdlib "mime/multipart" Reader - mfr := NewMultiFileReader(sf, true) - mpReader := multipart.NewReader(mfr, mfr.Boundary()) - - part, err := mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - mpf, err := NewFileFromPart(part) - 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() != "file.txt" { - t.Fatal("Expected filename to be \"file.txt\"") - } - if n, err := mpf.Read(buf); n != len(text) || err != nil { - t.Fatal("Expected to read from file", n, err) - } - if string(buf[:len(text)]) != text { - t.Fatal("Data read was different than expected") - } - - part, err = mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - mpf, err = NewFileFromPart(part) - 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() != "boop" { - t.Fatal("Expected filename to be \"boop\"") - } - - part, err = mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - child, err := NewFileFromPart(part) - if child == nil || err != nil { - t.Fatal("Expected to be able to read a child file") - } - if child.IsDirectory() { - t.Fatal("Expected file to not be a directory") - } - if child.FileName() != "boop/a.txt" { - t.Fatal("Expected filename to be \"some/file/path\"") - } - - part, err = mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - child, err = NewFileFromPart(part) - if child == nil || err != nil { - t.Fatal("Expected to be able to read a child file") - } - if child.IsDirectory() { - t.Fatal("Expected file to not be a directory") - } - if child.FileName() != "boop/b.txt" { - t.Fatal("Expected filename to be \"some/file/path\"") - } - - child, err = mpf.NextFile() - if child != nil || err != io.EOF { - t.Fatal("Expected to get (nil, io.EOF)") - } - - part, err = mpReader.NextPart() - if part == nil || err != nil { - t.Fatal("Expected non-nil part, nil error") - } - mpf, err = NewFileFromPart(part) - if mpf == nil || err != nil { - t.Fatal("Expected non-nil MultipartFile, nil error") - } - - part, err = mpReader.NextPart() - if part != nil || err != io.EOF { - t.Fatal("Expected to get (nil, io.EOF)") - } -} diff --git a/files/multipartfile.go b/files/multipartfile.go deleted file mode 100644 index 8a4b0b2..0000000 --- a/files/multipartfile.go +++ /dev/null @@ -1,118 +0,0 @@ -package files - -import ( - "io" - "io/ioutil" - "mime" - "mime/multipart" - "net/url" -) - -const ( - multipartFormdataType = "multipart/form-data" - multipartMixedType = "multipart/mixed" - - applicationDirectory = "application/x-directory" - applicationSymlink = "application/symlink" - applicationFile = "application/octet-stream" - - contentTypeHeader = "Content-Type" -) - -// MultipartFile implements File, and is created from a `multipart.Part`. -// It can be either a directory or file (checked by calling `IsDirectory()`). -type MultipartFile struct { - File - - Part *multipart.Part - Reader *multipart.Reader - Mediatype string -} - -func NewFileFromPart(part *multipart.Part) (File, error) { - f := &MultipartFile{ - Part: part, - } - - contentType := part.Header.Get(contentTypeHeader) - switch contentType { - case applicationSymlink: - out, err := ioutil.ReadAll(part) - if err != nil { - return nil, err - } - - return &Symlink{ - Target: string(out), - name: f.FileName(), - }, nil - case "": // default to application/octet-stream - fallthrough - case applicationFile: - return &ReaderFile{ - reader: part, - filename: f.FileName(), - abspath: part.Header.Get("abspath"), - fullpath: f.FullPath(), - }, nil - } - - var err error - f.Mediatype, _, err = mime.ParseMediaType(contentType) - if err != nil { - return nil, err - } - - return f, nil -} - -func (f *MultipartFile) IsDirectory() bool { - return f.Mediatype == multipartFormdataType || f.Mediatype == applicationDirectory -} - -func (f *MultipartFile) NextFile() (File, error) { - if !f.IsDirectory() { - return nil, ErrNotDirectory - } - if f.Reader != nil { - part, err := f.Reader.NextPart() - if err != nil { - return nil, err - } - - return NewFileFromPart(part) - } - - return nil, io.EOF -} - -func (f *MultipartFile) FileName() string { - if f == nil || f.Part == nil { - return "" - } - - filename, err := url.QueryUnescape(f.Part.FileName()) - if err != nil { - // if there is a unescape error, just treat the name as unescaped - return f.Part.FileName() - } - return filename -} - -func (f *MultipartFile) FullPath() string { - return f.FileName() -} - -func (f *MultipartFile) Read(p []byte) (int, error) { - if f.IsDirectory() { - return 0, ErrNotReader - } - return f.Part.Read(p) -} - -func (f *MultipartFile) Close() error { - if f.IsDirectory() { - return ErrNotReader - } - return f.Part.Close() -} diff --git a/files/readerfile.go b/files/readerfile.go deleted file mode 100644 index 8636414..0000000 --- a/files/readerfile.go +++ /dev/null @@ -1,70 +0,0 @@ -package files - -import ( - "errors" - "io" - "os" - "path/filepath" -) - -// ReaderFile is a implementation of File created from an `io.Reader`. -// ReaderFiles are never directories, and can be read from and closed. -type ReaderFile struct { - filename string - fullpath string - abspath string - reader io.ReadCloser - stat os.FileInfo -} - -func NewReaderFile(filename, path string, reader io.ReadCloser, stat os.FileInfo) *ReaderFile { - return &ReaderFile{filename, path, path, reader, stat} -} - -func NewReaderPathFile(filename, path string, reader io.ReadCloser, stat os.FileInfo) (*ReaderFile, error) { - abspath, err := filepath.Abs(path) - if err != nil { - return nil, err - } - - return &ReaderFile{filename, path, abspath, reader, stat}, nil -} - -func (f *ReaderFile) IsDirectory() bool { - return false -} - -func (f *ReaderFile) NextFile() (File, error) { - return nil, ErrNotDirectory -} - -func (f *ReaderFile) FileName() string { - return f.filename -} - -func (f *ReaderFile) FullPath() string { - return f.fullpath -} - -func (f *ReaderFile) AbsPath() string { - return f.abspath -} - -func (f *ReaderFile) Read(p []byte) (int, error) { - return f.reader.Read(p) -} - -func (f *ReaderFile) Close() error { - return f.reader.Close() -} - -func (f *ReaderFile) Stat() os.FileInfo { - return f.stat -} - -func (f *ReaderFile) Size() (int64, error) { - if f.stat == nil { - return 0, errors.New("File size unknown") - } - return f.stat.Size(), nil -} diff --git a/files/serialfile.go b/files/serialfile.go deleted file mode 100644 index 15e6c90..0000000 --- a/files/serialfile.go +++ /dev/null @@ -1,153 +0,0 @@ -package files - -import ( - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "syscall" -) - -// serialFile implements File, and reads from a path on the OS filesystem. -// No more than one file will be opened at a time (directories will advance -// to the next file when NextFile() is called). -type serialFile struct { - name string - path string - files []os.FileInfo - stat os.FileInfo - current *File - handleHiddenFiles bool -} - -func NewSerialFile(name, path string, hidden bool, stat os.FileInfo) (File, error) { - switch mode := stat.Mode(); { - case mode.IsRegular(): - file, err := os.Open(path) - if err != nil { - return nil, err - } - return NewReaderPathFile(name, path, file, stat) - case mode.IsDir(): - // for directories, stat all of the contents first, so we know what files to - // open when NextFile() is called - contents, err := ioutil.ReadDir(path) - if err != nil { - return nil, err - } - return &serialFile{name, path, contents, stat, nil, hidden}, nil - case mode&os.ModeSymlink != 0: - target, err := os.Readlink(path) - if err != nil { - return nil, err - } - return NewLinkFile(name, path, target, stat), nil - default: - return nil, fmt.Errorf("Unrecognized file type for %s: %s", name, mode.String()) - } -} - -func (f *serialFile) IsDirectory() bool { - // non-directories get created as a ReaderFile, so serialFiles should only - // represent directories - return true -} - -func (f *serialFile) NextFile() (File, error) { - // if a file was opened previously, close it - err := f.Close() - if err != nil { - switch err2 := err.(type) { - case *os.PathError: - if err2.Err != os.ErrClosed { - return nil, err - } - default: - return nil, err - } - } - - // if there aren't any files left in the root directory, we're done - if len(f.files) == 0 { - return nil, io.EOF - } - - stat := f.files[0] - f.files = f.files[1:] - - for !f.handleHiddenFiles && strings.HasPrefix(stat.Name(), ".") { - if len(f.files) == 0 { - return nil, io.EOF - } - - stat = f.files[0] - f.files = f.files[1:] - } - - // open the next file - fileName := filepath.ToSlash(filepath.Join(f.name, stat.Name())) - filePath := filepath.ToSlash(filepath.Join(f.path, stat.Name())) - - // recursively call the constructor on the next file - // if it's a regular file, we will open it as a ReaderFile - // if it's a directory, files in it will be opened serially - sf, err := NewSerialFile(fileName, filePath, f.handleHiddenFiles, stat) - if err != nil { - return nil, err - } - - f.current = &sf - - return sf, nil -} - -func (f *serialFile) FileName() string { - return f.name -} - -func (f *serialFile) FullPath() string { - return f.path -} - -func (f *serialFile) Read(p []byte) (int, error) { - return 0, io.EOF -} - -func (f *serialFile) Close() error { - // close the current file if there is one - if f.current != nil { - err := (*f.current).Close() - // ignore EINVAL error, the file might have already been closed - if err != nil && err != syscall.EINVAL { - return err - } - } - - return nil -} - -func (f *serialFile) Stat() os.FileInfo { - return f.stat -} - -func (f *serialFile) Size() (int64, error) { - if !f.stat.IsDir() { - return f.stat.Size(), nil - } - - var du int64 - err := filepath.Walk(f.FullPath(), func(p string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - - if fi != nil && fi.Mode().IsRegular() { - du += fi.Size() - } - return nil - }) - - return du, err -} diff --git a/files/slicefile.go b/files/slicefile.go deleted file mode 100644 index 8d18dca..0000000 --- a/files/slicefile.go +++ /dev/null @@ -1,76 +0,0 @@ -package files - -import ( - "errors" - "io" -) - -// SliceFile implements File, and provides simple directory handling. -// It contains children files, and is created from a `[]File`. -// SliceFiles are always directories, and can't be read from or closed. -type SliceFile struct { - filename string - path string - files []File - n int -} - -func NewSliceFile(filename, path string, files []File) *SliceFile { - return &SliceFile{filename, path, files, 0} -} - -func (f *SliceFile) IsDirectory() bool { - return true -} - -func (f *SliceFile) NextFile() (File, error) { - if f.n >= len(f.files) { - return nil, io.EOF - } - file := f.files[f.n] - f.n++ - return file, nil -} - -func (f *SliceFile) FileName() string { - return f.filename -} - -func (f *SliceFile) FullPath() string { - return f.path -} - -func (f *SliceFile) Read(p []byte) (int, error) { - return 0, io.EOF -} - -func (f *SliceFile) Close() error { - return ErrNotReader -} - -func (f *SliceFile) Peek(n int) File { - return f.files[n] -} - -func (f *SliceFile) Length() int { - return len(f.files) -} - -func (f *SliceFile) Size() (int64, error) { - var size int64 - - for _, file := range f.files { - sizeFile, ok := file.(SizeFile) - if !ok { - return 0, errors.New("Could not get size of child file") - } - - s, err := sizeFile.Size() - if err != nil { - return 0, err - } - size += s - } - - return size, nil -} diff --git a/files/webfile.go b/files/webfile.go deleted file mode 100644 index fcf4412..0000000 --- a/files/webfile.go +++ /dev/null @@ -1,68 +0,0 @@ -package files - -import ( - "io" - "net/http" - "net/url" - "path/filepath" -) - -// WebFile is an implementation of File which reads it -// from a Web URL (http). A GET request will be performed -// against the source when calling Read(). -type WebFile struct { - body io.ReadCloser - url *url.URL -} - -// NewWebFile creates a WebFile with the given URL, which -// will be used to perform the GET request on Read(). -func NewWebFile(url *url.URL) *WebFile { - return &WebFile{ - url: url, - } -} - -// Read reads the File from it's web location. On the first -// call to Read, a GET request will be performed against the -// WebFile's URL, using Go's default HTTP client. Any further -// reads will keep reading from the HTTP Request body. -func (wf *WebFile) Read(b []byte) (int, error) { - if wf.body == nil { - resp, err := http.Get(wf.url.String()) - if err != nil { - return 0, err - } - wf.body = resp.Body - } - return wf.body.Read(b) -} - -// Close closes the WebFile (or the request body). -func (wf *WebFile) Close() error { - if wf.body == nil { - return nil - } - return wf.body.Close() -} - -// FullPath returns the "Host+Path" for this WebFile. -func (wf *WebFile) FullPath() string { - return wf.url.Host + wf.url.Path -} - -// FileName returns the last element of the URL -// path for this file. -func (wf *WebFile) FileName() string { - return filepath.Base(wf.url.Path) -} - -// IsDirectory returns false. -func (wf *WebFile) IsDirectory() bool { - return false -} - -// NextFile always returns an ErrNotDirectory error. -func (wf *WebFile) NextFile() (File, error) { - return nil, ErrNotDirectory -} diff --git a/files/webfile_test.go b/files/webfile_test.go deleted file mode 100644 index 889cdc4..0000000 --- a/files/webfile_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package files - -import ( - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "net/url" - "testing" -) - -func TestWebFile(t *testing.T) { - http.HandleFunc("/my/url/content.txt", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "Hello world!") - }) - - s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "Hello world!") - })) - defer s.Close() - - u, err := url.Parse(s.URL) - if err != nil { - t.Fatal(err) - } - wf := NewWebFile(u) - body, err := ioutil.ReadAll(wf) - if err != nil { - t.Fatal(err) - } - if string(body) != "Hello world!" { - t.Fatal("should have read the web file") - } -} diff --git a/package.json b/package.json index 71dcd0a..9565c7b 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,6 @@ "license": "MIT", "name": "go-ipfs-cmdkit", "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", - "version": "1.1.3" + "version": "1.2.0" }