mirror of
https://github.com/kopia/kopia.git
synced 2026-05-15 02:05:39 -04:00
dir api cleanup
This commit is contained in:
@@ -18,11 +18,6 @@
|
||||
newLine = []byte("\n")
|
||||
)
|
||||
|
||||
// Writer allows writing directories.
|
||||
type Writer interface {
|
||||
WriteEntry(e *Entry) error
|
||||
}
|
||||
|
||||
type writer struct {
|
||||
lastEntryType EntryType
|
||||
objectWriter io.Writer
|
||||
@@ -89,15 +84,10 @@ func (w *writer) WriteEntry(e *Entry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewWriter creates a Writer object that writes directory contents to the specified underlying writer.
|
||||
func NewWriter(w io.Writer) Writer {
|
||||
return &writer{
|
||||
func (dir Directory) writeJSON(w io.Writer) error {
|
||||
dw := &writer{
|
||||
objectWriter: w,
|
||||
}
|
||||
}
|
||||
|
||||
func WriteDir(w io.Writer, dir Directory) error {
|
||||
dw := NewWriter(w)
|
||||
|
||||
for _, d := range dir.Entries {
|
||||
if err := dw.WriteEntry(d); err != nil {
|
||||
@@ -108,25 +98,25 @@ func WriteDir(w io.Writer, dir Directory) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadDir(r io.Reader) (Directory, error) {
|
||||
func (dir *Directory) readJSON(r io.Reader) error {
|
||||
var err error
|
||||
|
||||
s := bufio.NewScanner(r)
|
||||
if !s.Scan() {
|
||||
return Directory{}, fmt.Errorf("empty file")
|
||||
return fmt.Errorf("empty file")
|
||||
}
|
||||
|
||||
if !bytes.Equal(s.Bytes(), header) {
|
||||
return Directory{}, fmt.Errorf("invalid header: expected '%v' got '%v'", header, s.Bytes())
|
||||
return fmt.Errorf("invalid header: expected '%v' got '%v'", header, s.Bytes())
|
||||
}
|
||||
|
||||
l := Directory{}
|
||||
var entries []*Entry
|
||||
|
||||
for s.Scan() {
|
||||
line := s.Bytes()
|
||||
var v serializedDirectoryEntryV1
|
||||
if err := json.Unmarshal(line, &v); err != nil {
|
||||
return Directory{}, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
e := &Entry{}
|
||||
@@ -135,24 +125,26 @@ func ReadDir(r io.Reader) (Directory, error) {
|
||||
e.GroupID = v.GroupID
|
||||
e.ObjectID, err = cas.ParseObjectID(v.ObjectID)
|
||||
if err != nil {
|
||||
return Directory{}, nil
|
||||
return nil
|
||||
}
|
||||
m, err := strconv.ParseInt(v.Mode, 8, 16)
|
||||
if err != nil {
|
||||
return Directory{}, nil
|
||||
return nil
|
||||
}
|
||||
e.Mode = int16(m)
|
||||
e.ModTime = v.ModTime
|
||||
e.Type = EntryType(v.Type)
|
||||
if e.Type == EntryTypeFile {
|
||||
if v.FileSize == nil {
|
||||
return Directory{}, fmt.Errorf("missing file size")
|
||||
return fmt.Errorf("missing file size")
|
||||
}
|
||||
|
||||
e.Size = *v.FileSize
|
||||
}
|
||||
|
||||
l.Entries = append(l.Entries, e)
|
||||
entries = append(entries, e)
|
||||
}
|
||||
return l, nil
|
||||
|
||||
dir.Entries = entries
|
||||
return nil
|
||||
}
|
||||
77
fs/dir_test.go
Normal file
77
fs/dir_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJSON(t *testing.T) {
|
||||
dir := Directory{
|
||||
Entries: []*Entry{
|
||||
&Entry{
|
||||
EntryMetadata: EntryMetadata{
|
||||
Type: EntryTypeDirectory,
|
||||
Name: "d1",
|
||||
Mode: 0555,
|
||||
ModTime: time.Unix(1458876568, 0),
|
||||
},
|
||||
ObjectID: "foo",
|
||||
},
|
||||
|
||||
&Entry{
|
||||
EntryMetadata: EntryMetadata{
|
||||
Type: EntryTypeDirectory,
|
||||
Name: "d2",
|
||||
Mode: 0754,
|
||||
ModTime: time.Unix(1451871568, 0),
|
||||
},
|
||||
ObjectID: "bar",
|
||||
},
|
||||
|
||||
&Entry{
|
||||
EntryMetadata: EntryMetadata{
|
||||
Type: EntryTypeFile,
|
||||
Name: "f1",
|
||||
Mode: 0644,
|
||||
ModTime: time.Unix(1451871368, 0),
|
||||
Size: 123456,
|
||||
},
|
||||
ObjectID: "baz",
|
||||
},
|
||||
|
||||
&Entry{
|
||||
EntryMetadata: EntryMetadata{
|
||||
Type: EntryTypeFile,
|
||||
Name: "f2",
|
||||
Mode: 0644,
|
||||
ModTime: time.Unix(1451871331, 123456789),
|
||||
Size: 12,
|
||||
},
|
||||
ObjectID: "qoo",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
b := bytes.NewBuffer(nil)
|
||||
dir.writeJSON(b)
|
||||
|
||||
assertLines(
|
||||
t,
|
||||
string(b.Bytes()),
|
||||
"DIRECTORY:v1",
|
||||
`{"name":"d1","type":"d","mode":"555","modified":"2016-03-25T03:29:28Z","objectID":"foo"}`,
|
||||
`{"name":"d2","type":"d","mode":"754","modified":"2016-01-04T01:39:28Z","objectID":"bar"}`,
|
||||
`{"name":"f1","type":"f","size":"123456","mode":"644","modified":"2016-01-04T01:36:08Z","objectID":"baz"}`,
|
||||
`{"name":"f2","type":"f","size":"12","mode":"644","modified":"2016-01-04T01:35:31.123456789Z","objectID":"qoo"}`,
|
||||
)
|
||||
}
|
||||
|
||||
func assertLines(t *testing.T, text string, expectedLines ...string) {
|
||||
expected := strings.Join(expectedLines, "\n") + "\n"
|
||||
if text != expected {
|
||||
t.Errorf("expected: '%v' got '%v'", expected, text)
|
||||
}
|
||||
}
|
||||
10
fs/upload.go
10
fs/upload.go
@@ -60,7 +60,7 @@ func (u *uploader) UploadDir(path string, previous cas.ObjectID) (cas.ObjectID,
|
||||
return previous, ErrUploadCancelled
|
||||
}
|
||||
|
||||
listing, err := u.lister.List(path)
|
||||
dir, err := u.lister.List(path)
|
||||
if err != nil {
|
||||
return cas.NullObjectID, err
|
||||
}
|
||||
@@ -69,15 +69,15 @@ func (u *uploader) UploadDir(path string, previous cas.ObjectID) (cas.ObjectID,
|
||||
|
||||
if previous != "" {
|
||||
if r, err := u.mgr.Open(previous); err == nil {
|
||||
cached, err = ReadDir(r)
|
||||
err = cached.readJSON(r)
|
||||
if err != nil {
|
||||
log.Printf("WARNING: unable to cached read directory: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
directoryMatchesCache := len(cached.Entries) == len(listing.Entries)
|
||||
for _, e := range listing.Entries {
|
||||
directoryMatchesCache := len(cached.Entries) == len(dir.Entries)
|
||||
for _, e := range dir.Entries {
|
||||
fullPath := filepath.Join(path, e.Name)
|
||||
|
||||
// See if we had this name during previous pass.
|
||||
@@ -124,7 +124,7 @@ func (u *uploader) UploadDir(path string, previous cas.ObjectID) (cas.ObjectID,
|
||||
)
|
||||
defer writer.Close()
|
||||
|
||||
WriteDir(writer, listing)
|
||||
dir.writeJSON(writer)
|
||||
|
||||
return writer.Result(true)
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestWriter(t *testing.T) {
|
||||
b := bytes.NewBuffer(nil)
|
||||
w := NewWriter(b)
|
||||
|
||||
w.WriteEntry(&Entry{
|
||||
EntryMetadata: EntryMetadata{
|
||||
Type: EntryTypeDirectory,
|
||||
Name: "d1",
|
||||
Mode: 0555,
|
||||
ModTime: time.Unix(1458876568, 0),
|
||||
},
|
||||
ObjectID: "foo",
|
||||
})
|
||||
|
||||
w.WriteEntry(&Entry{
|
||||
EntryMetadata: EntryMetadata{
|
||||
Type: EntryTypeDirectory,
|
||||
Name: "d2",
|
||||
Mode: 0754,
|
||||
ModTime: time.Unix(1451871568, 0),
|
||||
},
|
||||
ObjectID: "bar",
|
||||
})
|
||||
|
||||
w.WriteEntry(&Entry{
|
||||
EntryMetadata: EntryMetadata{
|
||||
Type: EntryTypeFile,
|
||||
Name: "f1",
|
||||
Mode: 0644,
|
||||
ModTime: time.Unix(1451871368, 0),
|
||||
Size: 123456,
|
||||
},
|
||||
ObjectID: "baz",
|
||||
})
|
||||
|
||||
w.WriteEntry(&Entry{
|
||||
EntryMetadata: EntryMetadata{
|
||||
Type: EntryTypeFile,
|
||||
Name: "f2",
|
||||
Mode: 0644,
|
||||
ModTime: time.Unix(1451871331, 123456789),
|
||||
Size: 12,
|
||||
},
|
||||
ObjectID: "qoo",
|
||||
})
|
||||
|
||||
assertLines(
|
||||
t,
|
||||
string(b.Bytes()),
|
||||
"DIRECTORY:v1",
|
||||
`{"name":"d1","type":"d","mode":"555","modified":"2016-03-25T03:29:28Z","objectID":"foo"}`,
|
||||
`{"name":"d2","type":"d","mode":"754","modified":"2016-01-04T01:39:28Z","objectID":"bar"}`,
|
||||
`{"name":"f1","type":"f","size":"123456","mode":"644","modified":"2016-01-04T01:36:08Z","objectID":"baz"}`,
|
||||
`{"name":"f2","type":"f","size":"12","mode":"644","modified":"2016-01-04T01:35:31.123456789Z","objectID":"qoo"}`,
|
||||
)
|
||||
}
|
||||
|
||||
func assertLines(t *testing.T, text string, expectedLines ...string) {
|
||||
expected := strings.Join(expectedLines, "\n") + "\n"
|
||||
if text != expected {
|
||||
t.Errorf("expected: '%v' got '%v'", expected, text)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user