aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2021-08-22 23:52:33 +0700
committerShulhan <ms@kilabit.info>2021-08-22 23:52:33 +0700
commita049bbc175338d591873f73028e728ed480447d7 (patch)
tree2884e80ba4985f040390a4a20dd948e994dd430d
parentc1bd3574758c7070eb405922b56f0dfa056cad01 (diff)
downloadpakakeh.go-a049bbc175338d591873f73028e728ed480447d7.tar.xz
lib/memfs: add method Save and Encode
The Save method will write the new content to file system and update the content of Node using Encode().
-rw-r--r--.gitignore1
-rw-r--r--lib/memfs/generate_test.go1
-rw-r--r--lib/memfs/generate_test/gen_test.go1
-rw-r--r--lib/memfs/memfs_test.go3
-rw-r--r--lib/memfs/node.go63
-rw-r--r--lib/memfs/node_test.go51
6 files changed, 120 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 01f500b9..69b1ab51 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,7 @@
/lib/git/testdata/repotest
/lib/hunspell/testdata/out.dic
/lib/io/testdata/output.txt
+/lib/memfs/testdata/node_save
/lib/mining/cmd/cart/cart
/lib/mining/cmd/crf/crf
/lib/mining/cmd/lnsmote/lnsmote
diff --git a/lib/memfs/generate_test.go b/lib/memfs/generate_test.go
index 61dad660..8d1bb939 100644
--- a/lib/memfs/generate_test.go
+++ b/lib/memfs/generate_test.go
@@ -11,6 +11,7 @@ func TestGenerate(t *testing.T) {
Root: "testdata",
Excludes: []string{
`^\..*`,
+ ".*/node_save$",
},
}
mfs, err := New(opts)
diff --git a/lib/memfs/generate_test/gen_test.go b/lib/memfs/generate_test/gen_test.go
index be1ddb44..d9d19a41 100644
--- a/lib/memfs/generate_test/gen_test.go
+++ b/lib/memfs/generate_test/gen_test.go
@@ -277,6 +277,7 @@ func init() {
},
Excludes: []string{
`^\..*`,
+ `.*/node_save$`,
},
},
}
diff --git a/lib/memfs/memfs_test.go b/lib/memfs/memfs_test.go
index 18dc1eab..4739df99 100644
--- a/lib/memfs/memfs_test.go
+++ b/lib/memfs/memfs_test.go
@@ -74,6 +74,7 @@ func TestNew(t *testing.T) {
Excludes: []string{
"memfs_generate.go$",
"direct$",
+ "node_save$",
},
},
expMapKeys: []string{
@@ -99,6 +100,7 @@ func TestNew(t *testing.T) {
`.*\.js$`,
"memfs_generate.go$",
"direct$",
+ "node_save$",
},
},
expMapKeys: []string{
@@ -123,6 +125,7 @@ func TestNew(t *testing.T) {
Excludes: []string{
"memfs_generate.go$",
"direct$",
+ "node_save$",
},
},
expMapKeys: []string{
diff --git a/lib/memfs/node.go b/lib/memfs/node.go
index c958ea90..849a3d33 100644
--- a/lib/memfs/node.go
+++ b/lib/memfs/node.go
@@ -176,6 +176,39 @@ func (leaf *Node) Decode() ([]byte, error) {
return leaf.plainv, nil
}
+//
+// Encode compress and set the content of Node.
+//
+func (leaf *Node) Encode(content []byte) (err error) {
+ logp := "Node.Encode"
+
+ leaf.plainv = content
+ leaf.lowerv = bytes.ToLower(content)
+
+ switch leaf.ContentEncoding {
+ case EncodingGzip:
+ var buf bytes.Buffer
+ gz := gzip.NewWriter(&buf)
+
+ _, err = gz.Write(content)
+ if err != nil {
+ _ = gz.Close()
+ return fmt.Errorf("%s: %w", logp, err)
+ }
+
+ err = gz.Close()
+ if err != nil {
+ return fmt.Errorf("%s: %w", logp, err)
+ }
+
+ leaf.V = libbytes.Copy(buf.Bytes())
+
+ default:
+ leaf.V = content
+ }
+ return nil
+}
+
func (leaf *Node) IsDir() bool {
return leaf.mode.IsDir()
}
@@ -257,6 +290,36 @@ func (leaf *Node) Readdir(count int) (fis []os.FileInfo, err error) {
}
//
+// Save the content to file system and update the content of Node.
+//
+func (leaf *Node) Save(content []byte) (err error) {
+ var (
+ logp = "Node.Save"
+ f *os.File
+ )
+ f, err = os.OpenFile(leaf.SysPath, os.O_WRONLY|os.O_TRUNC, leaf.mode.Perm())
+ if err != nil {
+ return fmt.Errorf("%s: %w", logp, err)
+ }
+ _, err = f.Write(content)
+ if err != nil {
+ return fmt.Errorf("%s: %w", logp, err)
+ }
+ err = f.Close()
+ if err != nil {
+ return fmt.Errorf("%s: %w", logp, err)
+ }
+ err = leaf.Encode(content)
+ if err != nil {
+ return fmt.Errorf("%s: %w", logp, err)
+ }
+
+ leaf.modTime = time.Now()
+ leaf.size = int64(len(content))
+ return nil
+}
+
+//
// Seek sets the offset for the next Read offset, interpreted according to
// whence: SeekStart means relative to the start of the file, SeekCurrent
// means relative to the current offset, and SeekEnd means relative to the
diff --git a/lib/memfs/node_test.go b/lib/memfs/node_test.go
index 5b6375e7..29198055 100644
--- a/lib/memfs/node_test.go
+++ b/lib/memfs/node_test.go
@@ -84,6 +84,7 @@ func TestNode_Readdir(t *testing.T) {
"index.css",
"index.html",
"index.js",
+ "node_save",
"plain",
}
@@ -116,6 +117,56 @@ func gotFileNames(fis []os.FileInfo) (names []string) {
return
}
+func TestNode_Save(t *testing.T) {
+ node := &Node{
+ SysPath: "testdata/node_save",
+ mode: 0600,
+ }
+
+ err := os.WriteFile(node.SysPath, []byte{}, node.mode.Perm())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ cases := []struct {
+ desc string
+ content []byte
+ contentEncoding string
+ expContent []byte
+ }{{
+ desc: "Without content encoding",
+ content: []byte("ABC"),
+ expContent: []byte("ABC"),
+ }, {
+ desc: "With content encoding is gzip",
+ contentEncoding: EncodingGzip,
+ content: []byte("ABC"),
+ expContent: []byte{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x72, 0x74, 0x72, 0x06, 0x04, 0x00,
+ 0x00, 0xff, 0xff, 0x48, 0x03, 0x83, 0xa3, 0x03,
+ 0x00, 0x00, 0x00,
+ },
+ }}
+
+ for _, c := range cases {
+ node.ContentEncoding = c.contentEncoding
+
+ err = node.Save(c.content)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := os.ReadFile(node.SysPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ test.Assert(t, c.desc+": file content", c.content, got)
+ test.Assert(t, c.desc+": node content", c.expContent, node.V)
+ }
+}
+
func TestNode_Seek(t *testing.T) {
node := &Node{
size: 3,