aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2021-07-18 05:19:41 +0700
committerShulhan <ms@kilabit.info>2021-07-25 03:47:52 +0700
commitdab97a3491f28010f81554e717076e1434604b48 (patch)
treeb7ff144082c2024fa1b0d32ac8d988d174b44631 /lib
parent7ba4011107d0c4d214cc7f9d2950f8741da01dc3 (diff)
downloadpakakeh.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.go10
-rw-r--r--lib/memfs/memfs_test.go116
-rw-r--r--lib/memfs/node.go32
-rw-r--r--lib/memfs/pathnode.go35
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.
//