diff options
| author | Shulhan <ms@kilabit.info> | 2021-07-18 05:19:41 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2021-07-25 03:47:52 +0700 |
| commit | dab97a3491f28010f81554e717076e1434604b48 (patch) | |
| tree | b7ff144082c2024fa1b0d32ac8d988d174b44631 /lib | |
| parent | 7ba4011107d0c4d214cc7f9d2950f8741da01dc3 (diff) | |
| download | pakakeh.go-dab97a3491f28010f81554e717076e1434604b48.tar.xz | |
lib/memfs: implement json.Marshaler on MemFS and Node
Previously, without MarshalJSON, encoding the MemFS or Node object will
result in incomplete information, for example, missing name, modification
time, and size.
This commit implement the json.Marshaler in MemFS which encode the
PathNode sorted by keys in ascending order.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/memfs/memfs.go | 10 | ||||
| -rw-r--r-- | lib/memfs/memfs_test.go | 116 | ||||
| -rw-r--r-- | lib/memfs/node.go | 32 | ||||
| -rw-r--r-- | lib/memfs/pathnode.go | 35 |
4 files changed, 193 insertions, 0 deletions
diff --git a/lib/memfs/memfs.go b/lib/memfs/memfs.go index f4371dc4..03fac234 100644 --- a/lib/memfs/memfs.go +++ b/lib/memfs/memfs.go @@ -351,6 +351,16 @@ func (mfs *MemFS) ListNames() (paths []string) { } // +// MarshalJSON encode the MemFS object into JSON format. +// +// The field that being encoded is the PathNode field, where the key sorted in +// ascending order. +// +func (mfs *MemFS) MarshalJSON() ([]byte, error) { + return mfs.PathNodes.MarshalJSON() +} + +// // MustGet return the Node representation of file in memory by its path if its // exist or nil the path is not exist. // diff --git a/lib/memfs/memfs_test.go b/lib/memfs/memfs_test.go index c7b57fbb..83c3c522 100644 --- a/lib/memfs/memfs_test.go +++ b/lib/memfs/memfs_test.go @@ -1,6 +1,7 @@ package memfs import ( + "encoding/json" "fmt" "log" "os" @@ -344,6 +345,121 @@ func TestMemFS_Get(t *testing.T) { } } +func TestMemFS_MarshalJSON(t *testing.T) { + logp := "MarshalJSON" + + opts := &Options{ + Root: "testdata/direct/", + } + mfs, err := New(opts) + if err != nil { + t.Fatal(err) + } + + got, err := json.MarshalIndent(mfs, "", "\t") + if err != nil { + t.Fatal(err) + } + + exp := `{ + "/": { + "path": "/", + "name": "/", + "mod_time_epoch": 1569586540, + "mod_time_rfc3339": "2019-09-27 12:15:40 +0000 UTC", + "mode_string": "drwxr-xr-x", + "size": 0, + "is_dir": true, + "childs": [ + { + "path": "/add", + "name": "add", + "mod_time_epoch": 1569586540, + "mod_time_rfc3339": "2019-09-27 12:15:40 +0000 UTC", + "mode_string": "drwxr-xr-x", + "size": 0, + "is_dir": true, + "childs": [ + { + "path": "/add/file", + "name": "file", + "mod_time_epoch": 1569586540, + "mod_time_rfc3339": "2019-09-27 12:15:40 +0000 UTC", + "mode_string": "-rw-r--r--", + "size": 22, + "is_dir": false, + "childs": [] + }, + { + "path": "/add/file2", + "name": "file2", + "mod_time_epoch": 1569586540, + "mod_time_rfc3339": "2019-09-27 12:15:40 +0000 UTC", + "mode_string": "-rw-r--r--", + "size": 24, + "is_dir": false, + "childs": [] + } + ] + } + ] + }, + "/add": { + "path": "/add", + "name": "add", + "mod_time_epoch": 1569586540, + "mod_time_rfc3339": "2019-09-27 12:15:40 +0000 UTC", + "mode_string": "drwxr-xr-x", + "size": 0, + "is_dir": true, + "childs": [ + { + "path": "/add/file", + "name": "file", + "mod_time_epoch": 1569586540, + "mod_time_rfc3339": "2019-09-27 12:15:40 +0000 UTC", + "mode_string": "-rw-r--r--", + "size": 22, + "is_dir": false, + "childs": [] + }, + { + "path": "/add/file2", + "name": "file2", + "mod_time_epoch": 1569586540, + "mod_time_rfc3339": "2019-09-27 12:15:40 +0000 UTC", + "mode_string": "-rw-r--r--", + "size": 24, + "is_dir": false, + "childs": [] + } + ] + }, + "/add/file": { + "path": "/add/file", + "name": "file", + "mod_time_epoch": 1569586540, + "mod_time_rfc3339": "2019-09-27 12:15:40 +0000 UTC", + "mode_string": "-rw-r--r--", + "size": 22, + "is_dir": false, + "childs": [] + }, + "/add/file2": { + "path": "/add/file2", + "name": "file2", + "mod_time_epoch": 1569586540, + "mod_time_rfc3339": "2019-09-27 12:15:40 +0000 UTC", + "mode_string": "-rw-r--r--", + "size": 24, + "is_dir": false, + "childs": [] + } +}` + + test.Assert(t, logp, exp, string(got)) +} + func TestMemFS_isIncluded(t *testing.T) { cases := []struct { desc string diff --git a/lib/memfs/node.go b/lib/memfs/node.go index 95847b79..e89ef99f 100644 --- a/lib/memfs/node.go +++ b/lib/memfs/node.go @@ -162,6 +162,15 @@ func (leaf *Node) IsDir() bool { return leaf.mode.IsDir() } +// +// MarshalJSON encode the node into JSON format. +// +func (leaf *Node) MarshalJSON() ([]byte, error) { + var buf bytes.Buffer + leaf.packAsJson(&buf) + return buf.Bytes(), nil +} + func (leaf *Node) ModTime() time.Time { return leaf.modTime } @@ -325,6 +334,29 @@ func (leaf *Node) generateFuncName(in string) { leaf.GenFuncName = "generate_" + syspath } +func (leaf *Node) packAsJson(buf *bytes.Buffer) { + _ = buf.WriteByte('{') + + _, _ = fmt.Fprintf(buf, `%q:%q,`, "path", leaf.Path) + _, _ = fmt.Fprintf(buf, `%q:%q,`, "name", leaf.name) + _, _ = fmt.Fprintf(buf, `%q:%d,`, "mod_time_epoch", leaf.modTime.Unix()) + _, _ = fmt.Fprintf(buf, `%q:%q,`, "mod_time_rfc3339", leaf.modTime.UTC()) + _, _ = fmt.Fprintf(buf, `%q:%q,`, "mode_string", leaf.mode) + _, _ = fmt.Fprintf(buf, `%q:%d,`, "size", leaf.size) + _, _ = fmt.Fprintf(buf, `%q:%t,`, "is_dir", leaf.IsDir()) + + _, _ = fmt.Fprintf(buf, `%q:[`, "childs") + for x, child := range leaf.Childs { + if x > 0 { + _ = buf.WriteByte(',') + } + child.packAsJson(buf) + } + _ = buf.WriteByte(']') + + _ = buf.WriteByte('}') +} + // // removeChild remove a children node from list. If child is not exist, it // will return nil. diff --git a/lib/memfs/pathnode.go b/lib/memfs/pathnode.go index 87653c6e..032b0dac 100644 --- a/lib/memfs/pathnode.go +++ b/lib/memfs/pathnode.go @@ -4,6 +4,12 @@ package memfs +import ( + "bytes" + "fmt" + "sort" +) + // // PathNode contains a mapping between path and Node. // @@ -39,6 +45,35 @@ func (pn *PathNode) Get(path string) *Node { return nil } +func (pn *PathNode) MarshalJSON() ([]byte, error) { + // Merge the path with function to node into v. + for k, fn := range pn.f { + pn.v[k] = fn() + } + + buf := bytes.Buffer{} + + // Sort the paths. + keys := make([]string, 0, len(pn.v)) + for path := range pn.v { + keys = append(keys, path) + } + sort.Strings(keys) + + _ = buf.WriteByte('{') + for x, key := range keys { + if x > 0 { + _ = buf.WriteByte(',') + } + fmt.Fprintf(&buf, "%q:", key) + node := pn.v[key] + node.packAsJson(&buf) + } + _ = buf.WriteByte('}') + + return buf.Bytes(), nil +} + // // Set mapping of path to Node. // |
