refactor(ax): replace placeholder doc comments
This commit is contained in:
parent
0cb59850f5
commit
d900a785e7
12 changed files with 26 additions and 352 deletions
|
|
@ -70,10 +70,8 @@ func FromTar(data []byte) (*Medium, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Snapshot serialises the entire filesystem to a tarball.
|
||||
// Example: snapshot, _ := medium.Snapshot()
|
||||
// Use this for crash reports, workspace packaging, or TIM creation.
|
||||
//
|
||||
// result := m.Snapshot(...)
|
||||
func (m *Medium) Snapshot() ([]byte, error) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
|
@ -84,9 +82,7 @@ func (m *Medium) Snapshot() ([]byte, error) {
|
|||
return data, nil
|
||||
}
|
||||
|
||||
// Restore replaces the filesystem contents from a tarball.
|
||||
//
|
||||
// result := m.Restore(...)
|
||||
// Example: _ = medium.Restore(snapshot)
|
||||
func (m *Medium) Restore(data []byte) error {
|
||||
dataNode, err := borgdatanode.FromTar(data)
|
||||
if err != nil {
|
||||
|
|
@ -99,10 +95,8 @@ func (m *Medium) Restore(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// DataNode returns the underlying Borg DataNode.
|
||||
// Example: dataNode := medium.DataNode()
|
||||
// Use this to wrap the filesystem in a TIM container.
|
||||
//
|
||||
// result := m.DataNode(...)
|
||||
func (m *Medium) DataNode() *borgdatanode.DataNode {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
|
|
|||
64
io.go
64
io.go
|
|
@ -142,51 +142,37 @@ func NewSandboxed(root string) (Medium, error) {
|
|||
|
||||
// --- Helper Functions ---
|
||||
|
||||
// Read retrieves the content of a file from the given medium.
|
||||
//
|
||||
// result := io.Read(...)
|
||||
// Example: content, _ := io.Read(medium, "config/app.yaml")
|
||||
func Read(m Medium, path string) (string, error) {
|
||||
return m.Read(path)
|
||||
}
|
||||
|
||||
// Write saves the given content to a file in the given medium.
|
||||
//
|
||||
// result := io.Write(...)
|
||||
// Example: _ = io.Write(medium, "config/app.yaml", "port: 8080")
|
||||
func Write(m Medium, path, content string) error {
|
||||
return m.Write(path, content)
|
||||
}
|
||||
|
||||
// ReadStream returns a reader for the file content from the given medium.
|
||||
//
|
||||
// result := io.ReadStream(...)
|
||||
// Example: reader, _ := io.ReadStream(medium, "logs/app.log")
|
||||
func ReadStream(m Medium, path string) (goio.ReadCloser, error) {
|
||||
return m.ReadStream(path)
|
||||
}
|
||||
|
||||
// WriteStream returns a writer for the file content in the given medium.
|
||||
//
|
||||
// result := io.WriteStream(...)
|
||||
// Example: writer, _ := io.WriteStream(medium, "logs/app.log")
|
||||
func WriteStream(m Medium, path string) (goio.WriteCloser, error) {
|
||||
return m.WriteStream(path)
|
||||
}
|
||||
|
||||
// EnsureDir makes sure a directory exists in the given medium.
|
||||
//
|
||||
// result := io.EnsureDir(...)
|
||||
// Example: _ = io.EnsureDir(medium, "config")
|
||||
func EnsureDir(m Medium, path string) error {
|
||||
return m.EnsureDir(path)
|
||||
}
|
||||
|
||||
// IsFile checks if a path exists and is a regular file in the given medium.
|
||||
//
|
||||
// result := io.IsFile(...)
|
||||
// Example: ok := io.IsFile(medium, "config/app.yaml")
|
||||
func IsFile(m Medium, path string) bool {
|
||||
return m.IsFile(path)
|
||||
}
|
||||
|
||||
// Copy copies a file from one medium to another.
|
||||
//
|
||||
// result := io.Copy(...)
|
||||
// Example: _ = io.Copy(source, "input.txt", destination, "backup/input.txt")
|
||||
func Copy(source Medium, sourcePath string, destination Medium, destinationPath string) error {
|
||||
content, err := source.Read(sourcePath)
|
||||
if err != nil {
|
||||
|
|
@ -221,8 +207,6 @@ func NewMockMedium() *MockMedium {
|
|||
}
|
||||
|
||||
// Read retrieves the content of a file from the mock filesystem.
|
||||
//
|
||||
// result := m.Read(...)
|
||||
func (m *MockMedium) Read(path string) (string, error) {
|
||||
content, ok := m.Files[path]
|
||||
if !ok {
|
||||
|
|
@ -232,8 +216,6 @@ func (m *MockMedium) Read(path string) (string, error) {
|
|||
}
|
||||
|
||||
// Write saves the given content to a file in the mock filesystem.
|
||||
//
|
||||
// result := m.Write(...)
|
||||
func (m *MockMedium) Write(path, content string) error {
|
||||
m.Files[path] = content
|
||||
m.ModTimes[path] = time.Now()
|
||||
|
|
@ -245,38 +227,28 @@ func (m *MockMedium) WriteMode(path, content string, mode fs.FileMode) error {
|
|||
}
|
||||
|
||||
// EnsureDir records that a directory exists in the mock filesystem.
|
||||
//
|
||||
// result := m.EnsureDir(...)
|
||||
func (m *MockMedium) EnsureDir(path string) error {
|
||||
m.Dirs[path] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsFile checks if a path exists as a file in the mock filesystem.
|
||||
//
|
||||
// result := m.IsFile(...)
|
||||
func (m *MockMedium) IsFile(path string) bool {
|
||||
_, ok := m.Files[path]
|
||||
return ok
|
||||
}
|
||||
|
||||
// FileGet is a convenience function that reads a file from the mock filesystem.
|
||||
//
|
||||
// result := m.FileGet(...)
|
||||
func (m *MockMedium) FileGet(path string) (string, error) {
|
||||
return m.Read(path)
|
||||
}
|
||||
|
||||
// FileSet is a convenience function that writes a file to the mock filesystem.
|
||||
//
|
||||
// result := m.FileSet(...)
|
||||
func (m *MockMedium) FileSet(path, content string) error {
|
||||
return m.Write(path, content)
|
||||
}
|
||||
|
||||
// Delete removes a file or empty directory from the mock filesystem.
|
||||
//
|
||||
// result := m.Delete(...)
|
||||
func (m *MockMedium) Delete(path string) error {
|
||||
if _, ok := m.Files[path]; ok {
|
||||
delete(m.Files, path)
|
||||
|
|
@ -305,8 +277,6 @@ func (m *MockMedium) Delete(path string) error {
|
|||
}
|
||||
|
||||
// DeleteAll removes a file or directory and all contents from the mock filesystem.
|
||||
//
|
||||
// result := m.DeleteAll(...)
|
||||
func (m *MockMedium) DeleteAll(path string) error {
|
||||
found := false
|
||||
if _, ok := m.Files[path]; ok {
|
||||
|
|
@ -343,8 +313,6 @@ func (m *MockMedium) DeleteAll(path string) error {
|
|||
}
|
||||
|
||||
// Rename moves a file or directory in the mock filesystem.
|
||||
//
|
||||
// result := m.Rename(...)
|
||||
func (m *MockMedium) Rename(oldPath, newPath string) error {
|
||||
if content, ok := m.Files[oldPath]; ok {
|
||||
m.Files[newPath] = content
|
||||
|
|
@ -404,8 +372,6 @@ func (m *MockMedium) Rename(oldPath, newPath string) error {
|
|||
}
|
||||
|
||||
// Open opens a file from the mock filesystem.
|
||||
//
|
||||
// result := m.Open(...)
|
||||
func (m *MockMedium) Open(path string) (fs.File, error) {
|
||||
content, ok := m.Files[path]
|
||||
if !ok {
|
||||
|
|
@ -418,8 +384,6 @@ func (m *MockMedium) Open(path string) (fs.File, error) {
|
|||
}
|
||||
|
||||
// Create creates a file in the mock filesystem.
|
||||
//
|
||||
// result := m.Create(...)
|
||||
func (m *MockMedium) Create(path string) (goio.WriteCloser, error) {
|
||||
return &MockWriteCloser{
|
||||
medium: m,
|
||||
|
|
@ -428,8 +392,6 @@ func (m *MockMedium) Create(path string) (goio.WriteCloser, error) {
|
|||
}
|
||||
|
||||
// Append opens a file for appending in the mock filesystem.
|
||||
//
|
||||
// result := m.Append(...)
|
||||
func (m *MockMedium) Append(path string) (goio.WriteCloser, error) {
|
||||
content := m.Files[path]
|
||||
return &MockWriteCloser{
|
||||
|
|
@ -440,15 +402,11 @@ func (m *MockMedium) Append(path string) (goio.WriteCloser, error) {
|
|||
}
|
||||
|
||||
// ReadStream returns a reader for the file content in the mock filesystem.
|
||||
//
|
||||
// result := m.ReadStream(...)
|
||||
func (m *MockMedium) ReadStream(path string) (goio.ReadCloser, error) {
|
||||
return m.Open(path)
|
||||
}
|
||||
|
||||
// WriteStream returns a writer for the file content in the mock filesystem.
|
||||
//
|
||||
// result := m.WriteStream(...)
|
||||
func (m *MockMedium) WriteStream(path string) (goio.WriteCloser, error) {
|
||||
return m.Create(path)
|
||||
}
|
||||
|
|
@ -499,8 +457,6 @@ func (w *MockWriteCloser) Close() error {
|
|||
}
|
||||
|
||||
// List returns directory entries for the mock filesystem.
|
||||
//
|
||||
// result := m.List(...)
|
||||
func (m *MockMedium) List(path string) ([]fs.DirEntry, error) {
|
||||
if _, ok := m.Dirs[path]; !ok {
|
||||
// Check if it's the root or has children
|
||||
|
|
@ -610,8 +566,6 @@ func (m *MockMedium) List(path string) ([]fs.DirEntry, error) {
|
|||
}
|
||||
|
||||
// Stat returns file information for the mock filesystem.
|
||||
//
|
||||
// result := m.Stat(...)
|
||||
func (m *MockMedium) Stat(path string) (fs.FileInfo, error) {
|
||||
if content, ok := m.Files[path]; ok {
|
||||
modTime, ok := m.ModTimes[path]
|
||||
|
|
@ -636,8 +590,6 @@ func (m *MockMedium) Stat(path string) (fs.FileInfo, error) {
|
|||
}
|
||||
|
||||
// Exists checks if a path exists in the mock filesystem.
|
||||
//
|
||||
// result := m.Exists(...)
|
||||
func (m *MockMedium) Exists(path string) bool {
|
||||
if _, ok := m.Files[path]; ok {
|
||||
return true
|
||||
|
|
@ -649,8 +601,6 @@ func (m *MockMedium) Exists(path string) bool {
|
|||
}
|
||||
|
||||
// IsDir checks if a path is a directory in the mock filesystem.
|
||||
//
|
||||
// result := m.IsDir(...)
|
||||
func (m *MockMedium) IsDir(path string) bool {
|
||||
_, ok := m.Dirs[path]
|
||||
return ok
|
||||
|
|
|
|||
|
|
@ -241,8 +241,6 @@ func (m *Medium) validatePath(path string) (string, error) {
|
|||
}
|
||||
|
||||
// Read returns file contents as string.
|
||||
//
|
||||
// result := m.Read(...)
|
||||
func (m *Medium) Read(path string) (string, error) {
|
||||
resolvedPath, err := m.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -254,16 +252,12 @@ func (m *Medium) Read(path string) (string, error) {
|
|||
// Write saves content to file, creating parent directories as needed.
|
||||
// Files are created with mode 0644. For sensitive files (keys, secrets),
|
||||
// use WriteMode with 0600.
|
||||
//
|
||||
// result := m.Write(...)
|
||||
func (m *Medium) Write(path, content string) error {
|
||||
return m.WriteMode(path, content, 0644)
|
||||
}
|
||||
|
||||
// WriteMode saves content to file with explicit permissions.
|
||||
// Use 0600 for sensitive files (encryption output, private keys, auth hashes).
|
||||
//
|
||||
// result := m.WriteMode(...)
|
||||
func (m *Medium) WriteMode(path, content string, mode fs.FileMode) error {
|
||||
resolvedPath, err := m.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -273,8 +267,6 @@ func (m *Medium) WriteMode(path, content string, mode fs.FileMode) error {
|
|||
}
|
||||
|
||||
// EnsureDir creates directory if it doesn't exist.
|
||||
//
|
||||
// result := m.EnsureDir(...)
|
||||
func (m *Medium) EnsureDir(path string) error {
|
||||
resolvedPath, err := m.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -284,8 +276,6 @@ func (m *Medium) EnsureDir(path string) error {
|
|||
}
|
||||
|
||||
// IsDir returns true if path is a directory.
|
||||
//
|
||||
// result := m.IsDir(...)
|
||||
func (m *Medium) IsDir(path string) bool {
|
||||
if path == "" {
|
||||
return false
|
||||
|
|
@ -298,8 +288,6 @@ func (m *Medium) IsDir(path string) bool {
|
|||
}
|
||||
|
||||
// IsFile returns true if path is a regular file.
|
||||
//
|
||||
// result := m.IsFile(...)
|
||||
func (m *Medium) IsFile(path string) bool {
|
||||
if path == "" {
|
||||
return false
|
||||
|
|
@ -312,8 +300,6 @@ func (m *Medium) IsFile(path string) bool {
|
|||
}
|
||||
|
||||
// Exists returns true if path exists.
|
||||
//
|
||||
// result := m.Exists(...)
|
||||
func (m *Medium) Exists(path string) bool {
|
||||
resolvedPath, err := m.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -323,8 +309,6 @@ func (m *Medium) Exists(path string) bool {
|
|||
}
|
||||
|
||||
// List returns directory entries.
|
||||
//
|
||||
// result := m.List(...)
|
||||
func (m *Medium) List(path string) ([]fs.DirEntry, error) {
|
||||
resolvedPath, err := m.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -334,8 +318,6 @@ func (m *Medium) List(path string) ([]fs.DirEntry, error) {
|
|||
}
|
||||
|
||||
// Stat returns file info.
|
||||
//
|
||||
// result := m.Stat(...)
|
||||
func (m *Medium) Stat(path string) (fs.FileInfo, error) {
|
||||
resolvedPath, err := m.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -345,8 +327,6 @@ func (m *Medium) Stat(path string) (fs.FileInfo, error) {
|
|||
}
|
||||
|
||||
// Open opens the named file for reading.
|
||||
//
|
||||
// result := m.Open(...)
|
||||
func (m *Medium) Open(path string) (fs.File, error) {
|
||||
resolvedPath, err := m.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -356,8 +336,6 @@ func (m *Medium) Open(path string) (fs.File, error) {
|
|||
}
|
||||
|
||||
// Create creates or truncates the named file.
|
||||
//
|
||||
// result := m.Create(...)
|
||||
func (m *Medium) Create(path string) (goio.WriteCloser, error) {
|
||||
resolvedPath, err := m.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -367,8 +345,6 @@ func (m *Medium) Create(path string) (goio.WriteCloser, error) {
|
|||
}
|
||||
|
||||
// Append opens the named file for appending, creating it if it doesn't exist.
|
||||
//
|
||||
// result := m.Append(...)
|
||||
func (m *Medium) Append(path string) (goio.WriteCloser, error) {
|
||||
resolvedPath, err := m.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -383,8 +359,6 @@ func (m *Medium) Append(path string) (goio.WriteCloser, error) {
|
|||
// API, as required by the io.Medium interface, while Open provides the more
|
||||
// general filesystem-level operation. Both methods are kept for semantic
|
||||
// clarity and backward compatibility.
|
||||
//
|
||||
// result := m.ReadStream(...)
|
||||
func (m *Medium) ReadStream(path string) (goio.ReadCloser, error) {
|
||||
return m.Open(path)
|
||||
}
|
||||
|
|
@ -395,15 +369,11 @@ func (m *Medium) ReadStream(path string) (goio.ReadCloser, error) {
|
|||
// API, as required by the io.Medium interface, while Create provides the more
|
||||
// general filesystem-level operation. Both methods are kept for semantic
|
||||
// clarity and backward compatibility.
|
||||
//
|
||||
// result := m.WriteStream(...)
|
||||
func (m *Medium) WriteStream(path string) (goio.WriteCloser, error) {
|
||||
return m.Create(path)
|
||||
}
|
||||
|
||||
// Delete removes a file or empty directory.
|
||||
//
|
||||
// result := m.Delete(...)
|
||||
func (m *Medium) Delete(path string) error {
|
||||
resolvedPath, err := m.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -416,8 +386,6 @@ func (m *Medium) Delete(path string) error {
|
|||
}
|
||||
|
||||
// DeleteAll removes a file or directory recursively.
|
||||
//
|
||||
// result := m.DeleteAll(...)
|
||||
func (m *Medium) DeleteAll(path string) error {
|
||||
resolvedPath, err := m.validatePath(path)
|
||||
if err != nil {
|
||||
|
|
@ -430,8 +398,6 @@ func (m *Medium) DeleteAll(path string) error {
|
|||
}
|
||||
|
||||
// Rename moves a file or directory.
|
||||
//
|
||||
// result := m.Rename(...)
|
||||
func (m *Medium) Rename(oldPath, newPath string) error {
|
||||
oldResolvedPath, err := m.validatePath(oldPath)
|
||||
if err != nil {
|
||||
|
|
|
|||
52
node/node.go
52
node/node.go
|
|
@ -41,8 +41,6 @@ func New() *Node {
|
|||
// ---------- Node-specific methods ----------
|
||||
|
||||
// AddData stages content in the in-memory filesystem.
|
||||
//
|
||||
// result := n.AddData(...)
|
||||
func (n *Node) AddData(name string, content []byte) {
|
||||
name = core.TrimPrefix(name, "/")
|
||||
if name == "" {
|
||||
|
|
@ -60,8 +58,6 @@ func (n *Node) AddData(name string, content []byte) {
|
|||
}
|
||||
|
||||
// ToTar serialises the entire in-memory tree to a tar archive.
|
||||
//
|
||||
// result := n.ToTar(...)
|
||||
func (n *Node) ToTar() ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
tw := tar.NewWriter(buf)
|
||||
|
|
@ -89,8 +85,6 @@ func (n *Node) ToTar() ([]byte, error) {
|
|||
}
|
||||
|
||||
// FromTar creates a new Node from a tar archive.
|
||||
//
|
||||
// result := node.FromTar(...)
|
||||
func FromTar(data []byte) (*Node, error) {
|
||||
n := New()
|
||||
if err := n.LoadTar(data); err != nil {
|
||||
|
|
@ -100,8 +94,6 @@ func FromTar(data []byte) (*Node, error) {
|
|||
}
|
||||
|
||||
// LoadTar replaces the in-memory tree with the contents of a tar archive.
|
||||
//
|
||||
// result := n.LoadTar(...)
|
||||
func (n *Node) LoadTar(data []byte) error {
|
||||
newFiles := make(map[string]*dataFile)
|
||||
tr := tar.NewReader(bytes.NewReader(data))
|
||||
|
|
@ -137,8 +129,6 @@ func (n *Node) LoadTar(data []byte) error {
|
|||
}
|
||||
|
||||
// WalkNode walks the in-memory tree, calling fn for each entry.
|
||||
//
|
||||
// result := n.WalkNode(...)
|
||||
func (n *Node) WalkNode(root string, fn fs.WalkDirFunc) error {
|
||||
return fs.WalkDir(n, root, fn)
|
||||
}
|
||||
|
|
@ -156,8 +146,6 @@ type WalkOptions struct {
|
|||
}
|
||||
|
||||
// Walk walks the in-memory tree with optional WalkOptions.
|
||||
//
|
||||
// result := n.Walk(...)
|
||||
func (n *Node) Walk(root string, fn fs.WalkDirFunc, opts ...WalkOptions) error {
|
||||
var opt WalkOptions
|
||||
if len(opts) > 0 {
|
||||
|
|
@ -200,8 +188,6 @@ func (n *Node) Walk(root string, fn fs.WalkDirFunc, opts ...WalkOptions) error {
|
|||
|
||||
// ReadFile returns the content of the named file as a byte slice.
|
||||
// Implements fs.ReadFileFS.
|
||||
//
|
||||
// result := n.ReadFile(...)
|
||||
func (n *Node) ReadFile(name string) ([]byte, error) {
|
||||
name = core.TrimPrefix(name, "/")
|
||||
f, ok := n.files[name]
|
||||
|
|
@ -215,8 +201,6 @@ func (n *Node) ReadFile(name string) ([]byte, error) {
|
|||
}
|
||||
|
||||
// CopyFile copies a file from the in-memory tree to the local filesystem.
|
||||
//
|
||||
// result := n.CopyFile(...)
|
||||
func (n *Node) CopyFile(sourcePath, destinationPath string, perm fs.FileMode) error {
|
||||
sourcePath = core.TrimPrefix(sourcePath, "/")
|
||||
f, ok := n.files[sourcePath]
|
||||
|
|
@ -285,8 +269,6 @@ func (n *Node) CopyTo(target coreio.Medium, sourcePath, destPath string) error {
|
|||
// ---------- Medium interface: fs.FS methods ----------
|
||||
|
||||
// Open opens a file from the Node. Implements fs.FS.
|
||||
//
|
||||
// result := n.Open(...)
|
||||
func (n *Node) Open(name string) (fs.File, error) {
|
||||
name = core.TrimPrefix(name, "/")
|
||||
if file, ok := n.files[name]; ok {
|
||||
|
|
@ -306,8 +288,6 @@ func (n *Node) Open(name string) (fs.File, error) {
|
|||
}
|
||||
|
||||
// Stat returns file information for the given path.
|
||||
//
|
||||
// result := n.Stat(...)
|
||||
func (n *Node) Stat(name string) (fs.FileInfo, error) {
|
||||
name = core.TrimPrefix(name, "/")
|
||||
if file, ok := n.files[name]; ok {
|
||||
|
|
@ -327,8 +307,6 @@ func (n *Node) Stat(name string) (fs.FileInfo, error) {
|
|||
}
|
||||
|
||||
// ReadDir reads and returns all directory entries for the named directory.
|
||||
//
|
||||
// result := n.ReadDir(...)
|
||||
func (n *Node) ReadDir(name string) ([]fs.DirEntry, error) {
|
||||
name = core.TrimPrefix(name, "/")
|
||||
if name == "." {
|
||||
|
|
@ -381,8 +359,6 @@ func (n *Node) ReadDir(name string) ([]fs.DirEntry, error) {
|
|||
// ---------- Medium interface: read/write ----------
|
||||
|
||||
// Read retrieves the content of a file as a string.
|
||||
//
|
||||
// result := n.Read(...)
|
||||
func (n *Node) Read(filePath string) (string, error) {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
f, ok := n.files[filePath]
|
||||
|
|
@ -393,16 +369,12 @@ func (n *Node) Read(filePath string) (string, error) {
|
|||
}
|
||||
|
||||
// Write saves the given content to a file, overwriting it if it exists.
|
||||
//
|
||||
// result := n.Write(...)
|
||||
func (n *Node) Write(filePath, content string) error {
|
||||
n.AddData(filePath, []byte(content))
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteMode saves content with explicit permissions (no-op for in-memory node).
|
||||
//
|
||||
// result := n.WriteMode(...)
|
||||
func (n *Node) WriteMode(filePath, content string, mode fs.FileMode) error {
|
||||
return n.Write(filePath, content)
|
||||
}
|
||||
|
|
@ -416,8 +388,6 @@ func (n *Node) FileSet(filePath, content string) error {
|
|||
}
|
||||
|
||||
// EnsureDir is a no-op because directories are implicit in Node.
|
||||
//
|
||||
// result := n.EnsureDir(...)
|
||||
func (n *Node) EnsureDir(_ string) error {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -425,16 +395,12 @@ func (n *Node) EnsureDir(_ string) error {
|
|||
// ---------- Medium interface: existence checks ----------
|
||||
|
||||
// Exists checks if a path exists (file or directory).
|
||||
//
|
||||
// result := n.Exists(...)
|
||||
func (n *Node) Exists(filePath string) bool {
|
||||
_, err := n.Stat(filePath)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// IsFile checks if a path exists and is a regular file.
|
||||
//
|
||||
// result := n.IsFile(...)
|
||||
func (n *Node) IsFile(filePath string) bool {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
_, ok := n.files[filePath]
|
||||
|
|
@ -442,8 +408,6 @@ func (n *Node) IsFile(filePath string) bool {
|
|||
}
|
||||
|
||||
// IsDir checks if a path exists and is a directory.
|
||||
//
|
||||
// result := n.IsDir(...)
|
||||
func (n *Node) IsDir(filePath string) bool {
|
||||
info, err := n.Stat(filePath)
|
||||
if err != nil {
|
||||
|
|
@ -455,8 +419,6 @@ func (n *Node) IsDir(filePath string) bool {
|
|||
// ---------- Medium interface: mutations ----------
|
||||
|
||||
// Delete removes a single file.
|
||||
//
|
||||
// result := n.Delete(...)
|
||||
func (n *Node) Delete(filePath string) error {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
if _, ok := n.files[filePath]; ok {
|
||||
|
|
@ -467,8 +429,6 @@ func (n *Node) Delete(filePath string) error {
|
|||
}
|
||||
|
||||
// DeleteAll removes a file or directory and all children.
|
||||
//
|
||||
// result := n.DeleteAll(...)
|
||||
func (n *Node) DeleteAll(filePath string) error {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
|
||||
|
|
@ -493,8 +453,6 @@ func (n *Node) DeleteAll(filePath string) error {
|
|||
}
|
||||
|
||||
// Rename moves a file from oldPath to newPath.
|
||||
//
|
||||
// result := n.Rename(...)
|
||||
func (n *Node) Rename(oldPath, newPath string) error {
|
||||
oldPath = core.TrimPrefix(oldPath, "/")
|
||||
newPath = core.TrimPrefix(newPath, "/")
|
||||
|
|
@ -511,8 +469,6 @@ func (n *Node) Rename(oldPath, newPath string) error {
|
|||
}
|
||||
|
||||
// List returns directory entries for the given path.
|
||||
//
|
||||
// result := n.List(...)
|
||||
func (n *Node) List(filePath string) ([]fs.DirEntry, error) {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
if filePath == "" || filePath == "." {
|
||||
|
|
@ -525,8 +481,6 @@ func (n *Node) List(filePath string) ([]fs.DirEntry, error) {
|
|||
|
||||
// Create creates or truncates the named file, returning a WriteCloser.
|
||||
// Content is committed to the Node on Close.
|
||||
//
|
||||
// result := n.Create(...)
|
||||
func (n *Node) Create(filePath string) (goio.WriteCloser, error) {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
return &nodeWriter{node: n, path: filePath}, nil
|
||||
|
|
@ -534,8 +488,6 @@ func (n *Node) Create(filePath string) (goio.WriteCloser, error) {
|
|||
|
||||
// Append opens the named file for appending, creating it if needed.
|
||||
// Content is committed to the Node on Close.
|
||||
//
|
||||
// result := n.Append(...)
|
||||
func (n *Node) Append(filePath string) (goio.WriteCloser, error) {
|
||||
filePath = core.TrimPrefix(filePath, "/")
|
||||
var existing []byte
|
||||
|
|
@ -547,8 +499,6 @@ func (n *Node) Append(filePath string) (goio.WriteCloser, error) {
|
|||
}
|
||||
|
||||
// ReadStream returns a ReadCloser for the file content.
|
||||
//
|
||||
// result := n.ReadStream(...)
|
||||
func (n *Node) ReadStream(filePath string) (goio.ReadCloser, error) {
|
||||
f, err := n.Open(filePath)
|
||||
if err != nil {
|
||||
|
|
@ -558,8 +508,6 @@ func (n *Node) ReadStream(filePath string) (goio.ReadCloser, error) {
|
|||
}
|
||||
|
||||
// WriteStream returns a WriteCloser for the file content.
|
||||
//
|
||||
// result := n.WriteStream(...)
|
||||
func (n *Node) WriteStream(filePath string) (goio.WriteCloser, error) {
|
||||
return n.Create(filePath)
|
||||
}
|
||||
|
|
|
|||
38
s3/s3.go
38
s3/s3.go
|
|
@ -128,8 +128,6 @@ func (m *Medium) key(filePath string) string {
|
|||
}
|
||||
|
||||
// Read retrieves the content of a file as a string.
|
||||
//
|
||||
// result := m.Read(...)
|
||||
func (m *Medium) Read(filePath string) (string, error) {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -153,8 +151,6 @@ func (m *Medium) Read(filePath string) (string, error) {
|
|||
}
|
||||
|
||||
// Write saves the given content to a file, overwriting it if it exists.
|
||||
//
|
||||
// result := m.Write(...)
|
||||
func (m *Medium) Write(filePath, content string) error {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -173,22 +169,16 @@ func (m *Medium) Write(filePath, content string) error {
|
|||
}
|
||||
|
||||
// WriteMode ignores the requested mode because S3 objects do not store POSIX permissions.
|
||||
//
|
||||
// result := m.WriteMode(...)
|
||||
func (m *Medium) WriteMode(filePath, content string, _ fs.FileMode) error {
|
||||
return m.Write(filePath, content)
|
||||
}
|
||||
|
||||
// EnsureDir is a no-op for S3 (S3 has no real directories).
|
||||
//
|
||||
// result := m.EnsureDir(...)
|
||||
func (m *Medium) EnsureDir(_ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsFile checks if a path exists and is a regular file (not a "directory" prefix).
|
||||
//
|
||||
// result := m.IsFile(...)
|
||||
func (m *Medium) IsFile(filePath string) bool {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -206,22 +196,16 @@ func (m *Medium) IsFile(filePath string) bool {
|
|||
}
|
||||
|
||||
// FileGet is a convenience function that reads a file from the medium.
|
||||
//
|
||||
// result := m.FileGet(...)
|
||||
func (m *Medium) FileGet(filePath string) (string, error) {
|
||||
return m.Read(filePath)
|
||||
}
|
||||
|
||||
// FileSet is a convenience function that writes a file to the medium.
|
||||
//
|
||||
// result := m.FileSet(...)
|
||||
func (m *Medium) FileSet(filePath, content string) error {
|
||||
return m.Write(filePath, content)
|
||||
}
|
||||
|
||||
// Delete removes a single object.
|
||||
//
|
||||
// result := m.Delete(...)
|
||||
func (m *Medium) Delete(filePath string) error {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -239,8 +223,6 @@ func (m *Medium) Delete(filePath string) error {
|
|||
}
|
||||
|
||||
// DeleteAll removes all objects under the given prefix.
|
||||
//
|
||||
// result := m.DeleteAll(...)
|
||||
func (m *Medium) DeleteAll(filePath string) error {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -306,8 +288,6 @@ func (m *Medium) DeleteAll(filePath string) error {
|
|||
}
|
||||
|
||||
// Rename moves an object by copying then deleting the original.
|
||||
//
|
||||
// result := m.Rename(...)
|
||||
func (m *Medium) Rename(oldPath, newPath string) error {
|
||||
oldKey := m.key(oldPath)
|
||||
newKey := m.key(newPath)
|
||||
|
|
@ -338,8 +318,6 @@ func (m *Medium) Rename(oldPath, newPath string) error {
|
|||
}
|
||||
|
||||
// List returns directory entries for the given path using ListObjectsV2 with delimiter.
|
||||
//
|
||||
// result := m.List(...)
|
||||
func (m *Medium) List(filePath string) ([]fs.DirEntry, error) {
|
||||
prefix := m.key(filePath)
|
||||
if prefix != "" && !core.HasSuffix(prefix, "/") {
|
||||
|
|
@ -413,8 +391,6 @@ func (m *Medium) List(filePath string) ([]fs.DirEntry, error) {
|
|||
}
|
||||
|
||||
// Stat returns file information for the given path using HeadObject.
|
||||
//
|
||||
// result := m.Stat(...)
|
||||
func (m *Medium) Stat(filePath string) (fs.FileInfo, error) {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -448,8 +424,6 @@ func (m *Medium) Stat(filePath string) (fs.FileInfo, error) {
|
|||
}
|
||||
|
||||
// Open opens the named file for reading.
|
||||
//
|
||||
// result := m.Open(...)
|
||||
func (m *Medium) Open(filePath string) (fs.File, error) {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -489,8 +463,6 @@ func (m *Medium) Open(filePath string) (fs.File, error) {
|
|||
|
||||
// Create creates or truncates the named file. Returns a writer that
|
||||
// uploads the content on Close.
|
||||
//
|
||||
// result := m.Create(...)
|
||||
func (m *Medium) Create(filePath string) (goio.WriteCloser, error) {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -504,8 +476,6 @@ func (m *Medium) Create(filePath string) (goio.WriteCloser, error) {
|
|||
|
||||
// Append opens the named file for appending. It downloads the existing
|
||||
// content (if any) and re-uploads the combined content on Close.
|
||||
//
|
||||
// result := m.Append(...)
|
||||
func (m *Medium) Append(filePath string) (goio.WriteCloser, error) {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -530,8 +500,6 @@ func (m *Medium) Append(filePath string) (goio.WriteCloser, error) {
|
|||
}
|
||||
|
||||
// ReadStream returns a reader for the file content.
|
||||
//
|
||||
// result := m.ReadStream(...)
|
||||
func (m *Medium) ReadStream(filePath string) (goio.ReadCloser, error) {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -549,15 +517,11 @@ func (m *Medium) ReadStream(filePath string) (goio.ReadCloser, error) {
|
|||
}
|
||||
|
||||
// WriteStream returns a writer for the file content. Content is uploaded on Close.
|
||||
//
|
||||
// result := m.WriteStream(...)
|
||||
func (m *Medium) WriteStream(filePath string) (goio.WriteCloser, error) {
|
||||
return m.Create(filePath)
|
||||
}
|
||||
|
||||
// Exists checks if a path exists (file or directory prefix).
|
||||
//
|
||||
// result := m.Exists(...)
|
||||
func (m *Medium) Exists(filePath string) bool {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -590,8 +554,6 @@ func (m *Medium) Exists(filePath string) bool {
|
|||
}
|
||||
|
||||
// IsDir checks if a path exists and is a directory (has objects under it as a prefix).
|
||||
//
|
||||
// result := m.IsDir(...)
|
||||
func (m *Medium) IsDir(filePath string) bool {
|
||||
key := m.key(filePath)
|
||||
if key == "" {
|
||||
|
|
|
|||
|
|
@ -62,8 +62,6 @@ type PreObfuscator interface {
|
|||
type XORObfuscator struct{}
|
||||
|
||||
// Obfuscate XORs the data with a key stream derived from the entropy.
|
||||
//
|
||||
// result := x.Obfuscate(...)
|
||||
func (x *XORObfuscator) Obfuscate(data []byte, entropy []byte) []byte {
|
||||
if len(data) == 0 {
|
||||
return data
|
||||
|
|
@ -72,8 +70,6 @@ func (x *XORObfuscator) Obfuscate(data []byte, entropy []byte) []byte {
|
|||
}
|
||||
|
||||
// Deobfuscate reverses the XOR transformation (XOR is symmetric).
|
||||
//
|
||||
// result := x.Deobfuscate(...)
|
||||
func (x *XORObfuscator) Deobfuscate(data []byte, entropy []byte) []byte {
|
||||
if len(data) == 0 {
|
||||
return data
|
||||
|
|
@ -128,8 +124,6 @@ func (x *XORObfuscator) deriveKeyStream(entropy []byte, length int) []byte {
|
|||
type ShuffleMaskObfuscator struct{}
|
||||
|
||||
// Obfuscate shuffles bytes and applies a mask derived from entropy.
|
||||
//
|
||||
// result := s.Obfuscate(...)
|
||||
func (s *ShuffleMaskObfuscator) Obfuscate(data []byte, entropy []byte) []byte {
|
||||
if len(data) == 0 {
|
||||
return data
|
||||
|
|
@ -157,8 +151,6 @@ func (s *ShuffleMaskObfuscator) Obfuscate(data []byte, entropy []byte) []byte {
|
|||
}
|
||||
|
||||
// Deobfuscate reverses the shuffle and mask operations.
|
||||
//
|
||||
// result := s.Deobfuscate(...)
|
||||
func (s *ShuffleMaskObfuscator) Deobfuscate(data []byte, entropy []byte) []byte {
|
||||
if len(data) == 0 {
|
||||
return data
|
||||
|
|
@ -291,8 +283,6 @@ func NewChaChaPolySigilWithObfuscator(key []byte, obfuscator PreObfuscator) (*Ch
|
|||
|
||||
// In encrypts the data with pre-obfuscation.
|
||||
// The flow is: plaintext -> obfuscate -> encrypt
|
||||
//
|
||||
// result := s.In(...)
|
||||
func (s *ChaChaPolySigil) In(data []byte) ([]byte, error) {
|
||||
if s.Key == nil {
|
||||
return nil, ErrNoKeyConfigured
|
||||
|
|
@ -332,8 +322,6 @@ func (s *ChaChaPolySigil) In(data []byte) ([]byte, error) {
|
|||
|
||||
// Out decrypts the data and reverses obfuscation.
|
||||
// The flow is: decrypt -> deobfuscate -> plaintext
|
||||
//
|
||||
// result := s.Out(...)
|
||||
func (s *ChaChaPolySigil) Out(data []byte) ([]byte, error) {
|
||||
if s.Key == nil {
|
||||
return nil, ErrNoKeyConfigured
|
||||
|
|
@ -378,8 +366,6 @@ func (s *ChaChaPolySigil) Out(data []byte) ([]byte, error) {
|
|||
// GetNonceFromCiphertext extracts the nonce from encrypted output.
|
||||
// This is provided for debugging/logging purposes only.
|
||||
// The nonce should NOT be stored separately in headers.
|
||||
//
|
||||
// result := sigil.GetNonceFromCiphertext(...)
|
||||
func GetNonceFromCiphertext(ciphertext []byte) ([]byte, error) {
|
||||
nonceSize := chacha20poly1305.NonceSizeX
|
||||
if len(ciphertext) < nonceSize {
|
||||
|
|
|
|||
|
|
@ -45,8 +45,6 @@ type Sigil interface {
|
|||
// stops immediately and returns nil with that error.
|
||||
//
|
||||
// To reverse a transmutation, call each sigil's Out method in reverse order.
|
||||
//
|
||||
// result := sigil.Transmute(...)
|
||||
func Transmute(data []byte, sigils []Sigil) ([]byte, error) {
|
||||
var err error
|
||||
for _, s := range sigils {
|
||||
|
|
@ -63,8 +61,6 @@ func Transmute(data []byte, sigils []Sigil) ([]byte, error) {
|
|||
// Each sigil's Out method is called in reverse order, with the output of one sigil
|
||||
// becoming the input of the next. If any sigil returns an error, Untransmute
|
||||
// stops immediately and returns nil with that error.
|
||||
//
|
||||
// result := sigil.Untransmute(...)
|
||||
func Untransmute(data []byte, sigils []Sigil) ([]byte, error) {
|
||||
var err error
|
||||
for i := len(sigils) - 1; i >= 0; i-- {
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ import (
|
|||
type ReverseSigil struct{}
|
||||
|
||||
// In reverses the bytes of the data.
|
||||
//
|
||||
// result := s.In(...)
|
||||
func (s *ReverseSigil) In(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
|
|
@ -39,8 +37,6 @@ func (s *ReverseSigil) In(data []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
// Out reverses the bytes of the data.
|
||||
//
|
||||
// result := s.Out(...)
|
||||
func (s *ReverseSigil) Out(data []byte) ([]byte, error) {
|
||||
return s.In(data)
|
||||
}
|
||||
|
|
@ -50,8 +46,6 @@ func (s *ReverseSigil) Out(data []byte) ([]byte, error) {
|
|||
type HexSigil struct{}
|
||||
|
||||
// In encodes the data to hexadecimal.
|
||||
//
|
||||
// result := s.In(...)
|
||||
func (s *HexSigil) In(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
|
|
@ -62,8 +56,6 @@ func (s *HexSigil) In(data []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
// Out decodes the data from hexadecimal.
|
||||
//
|
||||
// result := s.Out(...)
|
||||
func (s *HexSigil) Out(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
|
|
@ -78,8 +70,6 @@ func (s *HexSigil) Out(data []byte) ([]byte, error) {
|
|||
type Base64Sigil struct{}
|
||||
|
||||
// In encodes the data to base64.
|
||||
//
|
||||
// result := s.In(...)
|
||||
func (s *Base64Sigil) In(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
|
|
@ -90,8 +80,6 @@ func (s *Base64Sigil) In(data []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
// Out decodes the data from base64.
|
||||
//
|
||||
// result := s.Out(...)
|
||||
func (s *Base64Sigil) Out(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
|
|
@ -108,8 +96,6 @@ type GzipSigil struct {
|
|||
}
|
||||
|
||||
// In compresses the data using gzip.
|
||||
//
|
||||
// result := s.In(...)
|
||||
func (s *GzipSigil) In(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
|
|
@ -130,8 +116,6 @@ func (s *GzipSigil) In(data []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
// Out decompresses the data using gzip.
|
||||
//
|
||||
// result := s.Out(...)
|
||||
func (s *GzipSigil) Out(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
|
|
@ -153,8 +137,6 @@ func (s *GzipSigil) Out(data []byte) ([]byte, error) {
|
|||
type JSONSigil struct{ Indent bool }
|
||||
|
||||
// In compacts or indents the JSON data.
|
||||
//
|
||||
// result := s.In(...)
|
||||
func (s *JSONSigil) In(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
|
|
@ -177,8 +159,6 @@ func (s *JSONSigil) In(data []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
// Out is a no-op for JSONSigil.
|
||||
//
|
||||
// result := s.Out(...)
|
||||
func (s *JSONSigil) Out(data []byte) ([]byte, error) {
|
||||
// For simplicity, Out is a no-op. The primary use is formatting.
|
||||
return data, nil
|
||||
|
|
@ -199,8 +179,6 @@ func NewHashSigil(h crypto.Hash) *HashSigil {
|
|||
}
|
||||
|
||||
// In hashes the data.
|
||||
//
|
||||
// result := s.In(...)
|
||||
func (s *HashSigil) In(data []byte) ([]byte, error) {
|
||||
var h io.Writer
|
||||
switch s.Hash {
|
||||
|
|
@ -250,16 +228,12 @@ func (s *HashSigil) In(data []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
// Out is a no-op for HashSigil.
|
||||
//
|
||||
// result := s.Out(...)
|
||||
func (s *HashSigil) Out(data []byte) ([]byte, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// NewSigil is a factory function that returns a Sigil based on a string name.
|
||||
// It is the primary way to create Sigil instances.
|
||||
//
|
||||
// result := sigil.NewSigil(...)
|
||||
func NewSigil(name string) (Sigil, error) {
|
||||
switch name {
|
||||
case "reverse":
|
||||
|
|
|
|||
|
|
@ -81,8 +81,6 @@ func New(options Options) (*Medium, error) {
|
|||
}
|
||||
|
||||
// Close closes the underlying database connection.
|
||||
//
|
||||
// result := m.Close(...)
|
||||
func (m *Medium) Close() error {
|
||||
if m.database != nil {
|
||||
return m.database.Close()
|
||||
|
|
@ -101,8 +99,6 @@ func cleanPath(filePath string) string {
|
|||
}
|
||||
|
||||
// Read retrieves the content of a file as a string.
|
||||
//
|
||||
// result := m.Read(...)
|
||||
func (m *Medium) Read(filePath string) (string, error) {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -127,15 +123,11 @@ func (m *Medium) Read(filePath string) (string, error) {
|
|||
}
|
||||
|
||||
// Write saves the given content to a file, overwriting it if it exists.
|
||||
//
|
||||
// result := m.Write(...)
|
||||
func (m *Medium) Write(filePath, content string) error {
|
||||
return m.WriteMode(filePath, content, 0644)
|
||||
}
|
||||
|
||||
// WriteMode saves the given content with explicit permissions.
|
||||
//
|
||||
// result := m.WriteMode(...)
|
||||
func (m *Medium) WriteMode(filePath, content string, mode fs.FileMode) error {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -154,8 +146,6 @@ func (m *Medium) WriteMode(filePath, content string, mode fs.FileMode) error {
|
|||
}
|
||||
|
||||
// EnsureDir makes sure a directory exists, creating it if necessary.
|
||||
//
|
||||
// result := m.EnsureDir(...)
|
||||
func (m *Medium) EnsureDir(filePath string) error {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -175,8 +165,6 @@ func (m *Medium) EnsureDir(filePath string) error {
|
|||
}
|
||||
|
||||
// IsFile checks if a path exists and is a regular file.
|
||||
//
|
||||
// result := m.IsFile(...)
|
||||
func (m *Medium) IsFile(filePath string) bool {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -194,22 +182,16 @@ func (m *Medium) IsFile(filePath string) bool {
|
|||
}
|
||||
|
||||
// FileGet is a convenience function that reads a file from the medium.
|
||||
//
|
||||
// result := m.FileGet(...)
|
||||
func (m *Medium) FileGet(filePath string) (string, error) {
|
||||
return m.Read(filePath)
|
||||
}
|
||||
|
||||
// FileSet is a convenience function that writes a file to the medium.
|
||||
//
|
||||
// result := m.FileSet(...)
|
||||
func (m *Medium) FileSet(filePath, content string) error {
|
||||
return m.Write(filePath, content)
|
||||
}
|
||||
|
||||
// Delete removes a file or empty directory.
|
||||
//
|
||||
// result := m.Delete(...)
|
||||
func (m *Medium) Delete(filePath string) error {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -255,8 +237,6 @@ func (m *Medium) Delete(filePath string) error {
|
|||
}
|
||||
|
||||
// DeleteAll removes a file or directory and all its contents recursively.
|
||||
//
|
||||
// result := m.DeleteAll(...)
|
||||
func (m *Medium) DeleteAll(filePath string) error {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -281,8 +261,6 @@ func (m *Medium) DeleteAll(filePath string) error {
|
|||
}
|
||||
|
||||
// Rename moves a file or directory from oldPath to newPath.
|
||||
//
|
||||
// result := m.Rename(...)
|
||||
func (m *Medium) Rename(oldPath, newPath string) error {
|
||||
oldKey := cleanPath(oldPath)
|
||||
newKey := cleanPath(newPath)
|
||||
|
|
@ -381,8 +359,6 @@ func (m *Medium) Rename(oldPath, newPath string) error {
|
|||
}
|
||||
|
||||
// List returns the directory entries for the given path.
|
||||
//
|
||||
// result := m.List(...)
|
||||
func (m *Medium) List(filePath string) ([]fs.DirEntry, error) {
|
||||
prefix := cleanPath(filePath)
|
||||
if prefix != "" {
|
||||
|
|
@ -459,8 +435,6 @@ func (m *Medium) List(filePath string) ([]fs.DirEntry, error) {
|
|||
}
|
||||
|
||||
// Stat returns file information for the given path.
|
||||
//
|
||||
// result := m.Stat(...)
|
||||
func (m *Medium) Stat(filePath string) (fs.FileInfo, error) {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -492,8 +466,6 @@ func (m *Medium) Stat(filePath string) (fs.FileInfo, error) {
|
|||
}
|
||||
|
||||
// Open opens the named file for reading.
|
||||
//
|
||||
// result := m.Open(...)
|
||||
func (m *Medium) Open(filePath string) (fs.File, error) {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -526,8 +498,6 @@ func (m *Medium) Open(filePath string) (fs.File, error) {
|
|||
}
|
||||
|
||||
// Create creates or truncates the named file.
|
||||
//
|
||||
// result := m.Create(...)
|
||||
func (m *Medium) Create(filePath string) (goio.WriteCloser, error) {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -540,8 +510,6 @@ func (m *Medium) Create(filePath string) (goio.WriteCloser, error) {
|
|||
}
|
||||
|
||||
// Append opens the named file for appending, creating it if it doesn't exist.
|
||||
//
|
||||
// result := m.Append(...)
|
||||
func (m *Medium) Append(filePath string) (goio.WriteCloser, error) {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -564,8 +532,6 @@ func (m *Medium) Append(filePath string) (goio.WriteCloser, error) {
|
|||
}
|
||||
|
||||
// ReadStream returns a reader for the file content.
|
||||
//
|
||||
// result := m.ReadStream(...)
|
||||
func (m *Medium) ReadStream(filePath string) (goio.ReadCloser, error) {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -591,15 +557,11 @@ func (m *Medium) ReadStream(filePath string) (goio.ReadCloser, error) {
|
|||
}
|
||||
|
||||
// WriteStream returns a writer for the file content. Content is stored on Close.
|
||||
//
|
||||
// result := m.WriteStream(...)
|
||||
func (m *Medium) WriteStream(filePath string) (goio.WriteCloser, error) {
|
||||
return m.Create(filePath)
|
||||
}
|
||||
|
||||
// Exists checks if a path exists (file or directory).
|
||||
//
|
||||
// result := m.Exists(...)
|
||||
func (m *Medium) Exists(filePath string) bool {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
@ -618,8 +580,6 @@ func (m *Medium) Exists(filePath string) bool {
|
|||
}
|
||||
|
||||
// IsDir checks if a path exists and is a directory.
|
||||
//
|
||||
// result := m.IsDir(...)
|
||||
func (m *Medium) IsDir(filePath string) bool {
|
||||
key := cleanPath(filePath)
|
||||
if key == "" {
|
||||
|
|
|
|||
|
|
@ -34,23 +34,17 @@ func NewMedium(dbPath string) (*Medium, error) {
|
|||
return &Medium{store: store}, nil
|
||||
}
|
||||
|
||||
// AsMedium returns a Medium adapter for an existing Store.
|
||||
//
|
||||
// result := s.AsMedium(...)
|
||||
// Example: medium := kvStore.AsMedium()
|
||||
func (s *Store) AsMedium() *Medium {
|
||||
return &Medium{store: s}
|
||||
}
|
||||
|
||||
// Store returns the underlying KV store for direct access.
|
||||
//
|
||||
// result := m.Store(...)
|
||||
// Example: kvStore := medium.Store()
|
||||
func (m *Medium) Store() *Store {
|
||||
return m.store
|
||||
}
|
||||
|
||||
// Close closes the underlying store.
|
||||
//
|
||||
// result := m.Close(...)
|
||||
// Example: _ = medium.Close()
|
||||
func (m *Medium) Close() error {
|
||||
return m.store.Close()
|
||||
}
|
||||
|
|
@ -71,8 +65,6 @@ func splitPath(entryPath string) (group, key string) {
|
|||
}
|
||||
|
||||
// Read retrieves the value at group/key.
|
||||
//
|
||||
// result := m.Read(...)
|
||||
func (m *Medium) Read(entryPath string) (string, error) {
|
||||
group, key := splitPath(entryPath)
|
||||
if key == "" {
|
||||
|
|
@ -82,8 +74,6 @@ func (m *Medium) Read(entryPath string) (string, error) {
|
|||
}
|
||||
|
||||
// Write stores a value at group/key.
|
||||
//
|
||||
// result := m.Write(...)
|
||||
func (m *Medium) Write(entryPath, content string) error {
|
||||
group, key := splitPath(entryPath)
|
||||
if key == "" {
|
||||
|
|
@ -93,22 +83,16 @@ func (m *Medium) Write(entryPath, content string) error {
|
|||
}
|
||||
|
||||
// WriteMode ignores the requested mode because key-value entries do not store POSIX permissions.
|
||||
//
|
||||
// result := m.WriteMode(...)
|
||||
func (m *Medium) WriteMode(entryPath, content string, _ fs.FileMode) error {
|
||||
return m.Write(entryPath, content)
|
||||
}
|
||||
|
||||
// EnsureDir is a no-op — groups are created implicitly on Set.
|
||||
//
|
||||
// result := m.EnsureDir(...)
|
||||
func (m *Medium) EnsureDir(_ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsFile returns true if a group/key pair exists.
|
||||
//
|
||||
// result := m.IsFile(...)
|
||||
func (m *Medium) IsFile(entryPath string) bool {
|
||||
group, key := splitPath(entryPath)
|
||||
if key == "" {
|
||||
|
|
@ -127,8 +111,6 @@ func (m *Medium) FileSet(entryPath, content string) error {
|
|||
}
|
||||
|
||||
// Delete removes a key, or checks that a group is empty.
|
||||
//
|
||||
// result := m.Delete(...)
|
||||
func (m *Medium) Delete(entryPath string) error {
|
||||
group, key := splitPath(entryPath)
|
||||
if group == "" {
|
||||
|
|
@ -148,8 +130,6 @@ func (m *Medium) Delete(entryPath string) error {
|
|||
}
|
||||
|
||||
// DeleteAll removes a key, or all keys in a group.
|
||||
//
|
||||
// result := m.DeleteAll(...)
|
||||
func (m *Medium) DeleteAll(entryPath string) error {
|
||||
group, key := splitPath(entryPath)
|
||||
if group == "" {
|
||||
|
|
@ -162,8 +142,6 @@ func (m *Medium) DeleteAll(entryPath string) error {
|
|||
}
|
||||
|
||||
// Rename moves a key from one path to another.
|
||||
//
|
||||
// result := m.Rename(...)
|
||||
func (m *Medium) Rename(oldPath, newPath string) error {
|
||||
oldGroup, oldKey := splitPath(oldPath)
|
||||
newGroup, newKey := splitPath(newPath)
|
||||
|
|
@ -182,8 +160,6 @@ func (m *Medium) Rename(oldPath, newPath string) error {
|
|||
|
||||
// List returns directory entries. Empty path returns groups.
|
||||
// A group path returns keys in that group.
|
||||
//
|
||||
// result := m.List(...)
|
||||
func (m *Medium) List(entryPath string) ([]fs.DirEntry, error) {
|
||||
group, key := splitPath(entryPath)
|
||||
|
||||
|
|
@ -221,8 +197,6 @@ func (m *Medium) List(entryPath string) ([]fs.DirEntry, error) {
|
|||
}
|
||||
|
||||
// Stat returns file info for a group (dir) or key (file).
|
||||
//
|
||||
// result := m.Stat(...)
|
||||
func (m *Medium) Stat(entryPath string) (fs.FileInfo, error) {
|
||||
group, key := splitPath(entryPath)
|
||||
if group == "" {
|
||||
|
|
@ -246,8 +220,6 @@ func (m *Medium) Stat(entryPath string) (fs.FileInfo, error) {
|
|||
}
|
||||
|
||||
// Open opens a key for reading.
|
||||
//
|
||||
// result := m.Open(...)
|
||||
func (m *Medium) Open(entryPath string) (fs.File, error) {
|
||||
group, key := splitPath(entryPath)
|
||||
if key == "" {
|
||||
|
|
@ -261,8 +233,6 @@ func (m *Medium) Open(entryPath string) (fs.File, error) {
|
|||
}
|
||||
|
||||
// Create creates or truncates a key. Content is stored on Close.
|
||||
//
|
||||
// result := m.Create(...)
|
||||
func (m *Medium) Create(entryPath string) (goio.WriteCloser, error) {
|
||||
group, key := splitPath(entryPath)
|
||||
if key == "" {
|
||||
|
|
@ -272,8 +242,6 @@ func (m *Medium) Create(entryPath string) (goio.WriteCloser, error) {
|
|||
}
|
||||
|
||||
// Append opens a key for appending. Content is stored on Close.
|
||||
//
|
||||
// result := m.Append(...)
|
||||
func (m *Medium) Append(entryPath string) (goio.WriteCloser, error) {
|
||||
group, key := splitPath(entryPath)
|
||||
if key == "" {
|
||||
|
|
@ -284,8 +252,6 @@ func (m *Medium) Append(entryPath string) (goio.WriteCloser, error) {
|
|||
}
|
||||
|
||||
// ReadStream returns a reader for the value.
|
||||
//
|
||||
// result := m.ReadStream(...)
|
||||
func (m *Medium) ReadStream(entryPath string) (goio.ReadCloser, error) {
|
||||
group, key := splitPath(entryPath)
|
||||
if key == "" {
|
||||
|
|
@ -299,15 +265,11 @@ func (m *Medium) ReadStream(entryPath string) (goio.ReadCloser, error) {
|
|||
}
|
||||
|
||||
// WriteStream returns a writer. Content is stored on Close.
|
||||
//
|
||||
// result := m.WriteStream(...)
|
||||
func (m *Medium) WriteStream(entryPath string) (goio.WriteCloser, error) {
|
||||
return m.Create(entryPath)
|
||||
}
|
||||
|
||||
// Exists returns true if a group or key exists.
|
||||
//
|
||||
// result := m.Exists(...)
|
||||
func (m *Medium) Exists(entryPath string) bool {
|
||||
group, key := splitPath(entryPath)
|
||||
if group == "" {
|
||||
|
|
@ -322,8 +284,6 @@ func (m *Medium) Exists(entryPath string) bool {
|
|||
}
|
||||
|
||||
// IsDir returns true if the path is a group with entries.
|
||||
//
|
||||
// result := m.IsDir(...)
|
||||
func (m *Medium) IsDir(entryPath string) bool {
|
||||
group, key := splitPath(entryPath)
|
||||
if key != "" || group == "" {
|
||||
|
|
|
|||
|
|
@ -43,16 +43,12 @@ func New(dbPath string) (*Store, error) {
|
|||
return &Store{database: database}, nil
|
||||
}
|
||||
|
||||
// Close closes the underlying database.
|
||||
//
|
||||
// result := s.Close(...)
|
||||
// Example: _ = kvStore.Close()
|
||||
func (s *Store) Close() error {
|
||||
return s.database.Close()
|
||||
}
|
||||
|
||||
// Get retrieves a value by group and key.
|
||||
//
|
||||
// result := s.Get(...)
|
||||
// Example: theme, _ := kvStore.Get("app", "theme")
|
||||
func (s *Store) Get(group, key string) (string, error) {
|
||||
var value string
|
||||
err := s.database.QueryRow("SELECT value FROM kv WHERE grp = ? AND key = ?", group, key).Scan(&value)
|
||||
|
|
@ -65,9 +61,7 @@ func (s *Store) Get(group, key string) (string, error) {
|
|||
return value, nil
|
||||
}
|
||||
|
||||
// Set stores a value by group and key, overwriting if exists.
|
||||
//
|
||||
// result := s.Set(...)
|
||||
// Example: _ = kvStore.Set("app", "theme", "midnight")
|
||||
func (s *Store) Set(group, key, value string) error {
|
||||
_, err := s.database.Exec(
|
||||
`INSERT INTO kv (grp, key, value) VALUES (?, ?, ?)
|
||||
|
|
@ -80,9 +74,7 @@ func (s *Store) Set(group, key, value string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Delete removes a single key from a group.
|
||||
//
|
||||
// result := s.Delete(...)
|
||||
// Example: _ = kvStore.Delete("app", "theme")
|
||||
func (s *Store) Delete(group, key string) error {
|
||||
_, err := s.database.Exec("DELETE FROM kv WHERE grp = ? AND key = ?", group, key)
|
||||
if err != nil {
|
||||
|
|
@ -91,9 +83,7 @@ func (s *Store) Delete(group, key string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Count returns the number of keys in a group.
|
||||
//
|
||||
// result := s.Count(...)
|
||||
// Example: count, _ := kvStore.Count("app")
|
||||
func (s *Store) Count(group string) (int, error) {
|
||||
var count int
|
||||
err := s.database.QueryRow("SELECT COUNT(*) FROM kv WHERE grp = ?", group).Scan(&count)
|
||||
|
|
@ -103,9 +93,7 @@ func (s *Store) Count(group string) (int, error) {
|
|||
return count, nil
|
||||
}
|
||||
|
||||
// DeleteGroup removes all keys in a group.
|
||||
//
|
||||
// result := s.DeleteGroup(...)
|
||||
// Example: _ = kvStore.DeleteGroup("app")
|
||||
func (s *Store) DeleteGroup(group string) error {
|
||||
_, err := s.database.Exec("DELETE FROM kv WHERE grp = ?", group)
|
||||
if err != nil {
|
||||
|
|
@ -114,9 +102,7 @@ func (s *Store) DeleteGroup(group string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetAll returns all key-value pairs in a group.
|
||||
//
|
||||
// result := s.GetAll(...)
|
||||
// Example: values, _ := kvStore.GetAll("app")
|
||||
func (s *Store) GetAll(group string) (map[string]string, error) {
|
||||
rows, err := s.database.Query("SELECT key, value FROM kv WHERE grp = ?", group)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -77,11 +77,9 @@ func New(options Options) (*Service, error) {
|
|||
return s, nil
|
||||
}
|
||||
|
||||
// CreateWorkspace creates a new encrypted workspace.
|
||||
// Example: workspaceID, _ := service.CreateWorkspace("alice", "pass123")
|
||||
// Identifier is hashed (SHA-256) to create the directory name.
|
||||
// A PGP keypair is generated using the password.
|
||||
//
|
||||
// result := s.CreateWorkspace(...)
|
||||
func (s *Service) CreateWorkspace(identifier, password string) (string, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
|
@ -119,9 +117,7 @@ func (s *Service) CreateWorkspace(identifier, password string) (string, error) {
|
|||
return workspaceID, nil
|
||||
}
|
||||
|
||||
// SwitchWorkspace changes the active workspace.
|
||||
//
|
||||
// result := s.SwitchWorkspace(...)
|
||||
// Example: _ = service.SwitchWorkspace(workspaceID)
|
||||
func (s *Service) SwitchWorkspace(name string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
|
@ -155,9 +151,7 @@ func (s *Service) activeFilePath(operation, filename string) (string, error) {
|
|||
return filePath, nil
|
||||
}
|
||||
|
||||
// WorkspaceFileGet retrieves the content of a file from the active workspace.
|
||||
//
|
||||
// result := s.WorkspaceFileGet(...)
|
||||
// Example: content, _ := service.WorkspaceFileGet("notes/todo.txt")
|
||||
func (s *Service) WorkspaceFileGet(filename string) (string, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
|
@ -169,9 +163,7 @@ func (s *Service) WorkspaceFileGet(filename string) (string, error) {
|
|||
return s.medium.Read(filePath)
|
||||
}
|
||||
|
||||
// WorkspaceFileSet saves content to a file in the active workspace.
|
||||
//
|
||||
// result := s.WorkspaceFileSet(...)
|
||||
// Example: _ = service.WorkspaceFileSet("notes/todo.txt", "ship it")
|
||||
func (s *Service) WorkspaceFileSet(filename, content string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
|
@ -186,12 +178,12 @@ func (s *Service) WorkspaceFileSet(filename, content string) error {
|
|||
// HandleIPCEvents handles workspace-related IPC messages.
|
||||
//
|
||||
// service, _ := workspace.New(workspace.Options{Core: core.New(), Crypt: myCryptProvider})
|
||||
// result := service.HandleIPCEvents(core.New(), map[string]any{
|
||||
// ipcResult := service.HandleIPCEvents(core.New(), map[string]any{
|
||||
// "action": "workspace.create",
|
||||
// "identifier": "alice",
|
||||
// "password": "pass123",
|
||||
// })
|
||||
// _ = result.OK
|
||||
// _ = ipcResult.OK
|
||||
func (s *Service) HandleIPCEvents(_ *core.Core, message core.Message) core.Result {
|
||||
switch payload := message.(type) {
|
||||
case map[string]any:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue