Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Porting io/fs package #1323

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
8 changes: 4 additions & 4 deletions examples/gno.land/r/demo/boards/z_4_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ func main() {
// "Escaped": true,
// "ObjectID": "336074805fc853987abe6f7fe3ad97a6a6f3077a:2"
// },
// "Index": "188",
// "Index": "191",
// "TV": null
// }
// }
Expand Down Expand Up @@ -541,7 +541,7 @@ func main() {
// },
// "V": {
// "@type": "/gno.RefValue",
// "Hash": "8164abed5231309c88497013f7da72a1b5d427b0",
// "Hash": "40c644a23c5104a1d6695e17aeac3939dcfecf70",
// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:115"
// }
// },
Expand Down Expand Up @@ -847,7 +847,7 @@ func main() {
// },
// "V": {
// "@type": "/gno.RefValue",
// "Hash": "5b4b593f1d4b37cb99166247ea28174f91087fdd",
// "Hash": "8dbf25500e2f04e50584894e606ad0788fe6920d",
// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:82"
// }
// },
Expand All @@ -865,7 +865,7 @@ func main() {
// },
// "V": {
// "@type": "/gno.RefValue",
// "Hash": "7e9fd9bb5e90a06c7751585cd80f23aedddde25b",
// "Hash": "64d61e4f065f6d0760e37b76fbd832db903b68ec",
// "ObjectID": "f6dbf411da22e67d74cd7ddba6a76cd7e14a4822:83"
// }
// },
Expand Down
11 changes: 11 additions & 0 deletions gnovm/stdlibs/internal/oserror/errors.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package oserror

import "errors"

var (
ErrInvalid = errors.New("invalid argument")
ErrPermission = errors.New("permission denied")
ErrExist = errors.New("file already exists")
ErrNotExist = errors.New("file does not exist")
ErrClosed = errors.New("file closed")
)
76 changes: 76 additions & 0 deletions gnovm/stdlibs/io/fs/format.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fs

import (
"time"
)

// FormatFileInfo returns a formatted version of info for human readability.
// Implementations of [FileInfo] can call this from a String method.
// The output for a file named "hello.go", 100 bytes, mode 0o644, created
// January 1, 1970 at noon is
//
// -rw-r--r-- 100 1970-01-01 12:00:00 hello.go
func FormatFileInfo(info FileInfo) string {
name := info.Name()
b := make([]byte, 0, 40+len(name))
b = append(b, info.Mode().String()...)
b = append(b, ' ')

size := info.Size()
var usize uint64
if size >= 0 {
usize = uint64(size)
} else {
b = append(b, '-')
usize = uint64(-size)
}
var buf [20]byte
i := len(buf) - 1
for usize >= 10 {
q := usize / 10
buf[i] = byte('0' + usize - q*10)
i--
usize = q
}
buf[i] = byte('0' + usize)
b = append(b, buf[i:]...)
b = append(b, ' ')

b = append(b, info.ModTime().Format(time.DateTime)...)
b = append(b, ' ')

b = append(b, name...)
if info.IsDir() {
b = append(b, '/')
}

return string(b)
}

// FormatDirEntry returns a formatted version of dir for human readability.
// Implementations of [DirEntry] can call this from a String method.
// The outputs for a directory named subdir and a file named hello.go are:
//
// d subdir/
// - hello.go
func FormatDirEntry(dir DirEntry) string {
name := dir.Name()
b := make([]byte, 0, 5+len(name))

// The Type method does not return any permission bits,
// so strip them from the string.
mode := dir.Type().String()
mode = mode[:len(mode)-9]

b = append(b, mode...)
b = append(b, ' ')
b = append(b, name...)
if dir.IsDir() {
b = append(b, '/')
}
return string(b)
}
122 changes: 122 additions & 0 deletions gnovm/stdlibs/io/fs/format_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fs_test

import (
"io/fs"
"testing"
"time"
)

// formatTest implements FileInfo to test FormatFileInfo,
// and implements DirEntry to test FormatDirEntry.
type formatTest struct {
name string
size int64
mode fs.FileMode
modTime time.Time
isDir bool
}

func (fs *formatTest) Name() string {
return fs.name
}

func (fs *formatTest) Size() int64 {
return fs.size
}

func (fs *formatTest) Mode() fs.FileMode {
return fs.mode
}

func (fs *formatTest) ModTime() time.Time {
return fs.modTime
}

func (fs *formatTest) IsDir() bool {
return fs.isDir
}

func (fs *formatTest) Sys() interface{} {
return nil
}

func (fs *formatTest) Type() fs.FileMode {
return fs.mode.Type()
}

func (fs *formatTest) Info() (fs.FileInfo, error) {
return fs, nil
}

var formatTests = []struct {
input formatTest
wantFileInfo string
wantDirEntry string
}{
{
formatTest{
name: "hello.go",
size: 100,
mode: 0o644,
modTime: time.Date(1970, time.January, 1, 12, 0, 0, 0, time.UTC),
isDir: false,
},
"-rw-r--r-- 100 1970-01-01 12:00:00 hello.go",
"- hello.go",
},
{
formatTest{
name: "home/gopher",
size: 0,
mode: fs.ModeDir | 0o755,
modTime: time.Date(1970, time.January, 1, 12, 0, 0, 0, time.UTC),
isDir: true,
},
"drwxr-xr-x 0 1970-01-01 12:00:00 home/gopher/",
"d home/gopher/",
},
{
formatTest{
name: "big",
size: 0x7fffffffffffffff,
mode: fs.ModeIrregular | 0o644,
modTime: time.Date(1970, time.January, 1, 12, 0, 0, 0, time.UTC),
isDir: false,
},
"?rw-r--r-- 9223372036854775807 1970-01-01 12:00:00 big",
"? big",
},
{
formatTest{
name: "small",
size: -0x8000000000000000,
mode: fs.ModeSocket | fs.ModeSetuid | 0o644,
modTime: time.Date(1970, time.January, 1, 12, 0, 0, 0, time.UTC),
isDir: false,
},
"Surw-r--r-- -9223372036854775808 1970-01-01 12:00:00 small",
"S small",
},
}

func TestFormatFileInfo(t *testing.T) {
for i, test := range formatTests {
got := fs.FormatFileInfo(&test.input)
if got != test.wantFileInfo {
t.Errorf("%d: FormatFileInfo(%#v) = %q, want %q", i, test.input, got, test.wantFileInfo)
}
}
}

func TestFormatDirEntry(t *testing.T) {
for i, test := range formatTests {
got := fs.FormatDirEntry(&test.input)
if got != test.wantDirEntry {
t.Errorf("%d: FormatDirEntry(%#v) = %q, want %q", i, test.input, got, test.wantDirEntry)
}
}
}
Loading
Loading