Update fs for workspaces

This commit is contained in:
2024-10-14 21:26:31 +02:00
parent 2d2b596f2c
commit 97ebf1c08e
2 changed files with 46 additions and 133 deletions

View File

@@ -3,20 +3,14 @@ package filesystem
import ( import (
"errors" "errors"
"fmt" "fmt"
"novamd/internal/gitutils"
"novamd/internal/models"
"os" "os"
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"novamd/internal/models"
) )
type FileSystem struct { // FileNode represents a file or directory in the file system
RootDir string
GitRepo *gitutils.GitRepo
Settings *models.Settings
}
type FileNode struct { type FileNode struct {
ID string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
@@ -24,136 +18,72 @@ type FileNode struct {
Children []FileNode `json:"children,omitempty"` Children []FileNode `json:"children,omitempty"`
} }
func New(rootDir string, settings *models.Settings) *FileSystem { // ValidatePath ensures the given path is within the workspace
fs := &FileSystem{ func ValidatePath(workspace *models.Workspace, path string) (string, error) {
RootDir: rootDir, workspacePath := GetWorkspacePath(workspace)
Settings: settings, fullPath := filepath.Join(workspacePath, path)
}
if settings.Settings.GitEnabled {
fs.GitRepo = gitutils.New(
settings.Settings.GitURL,
settings.Settings.GitUser,
settings.Settings.GitToken,
rootDir,
)
}
return fs
}
func (fs *FileSystem) SetupGitRepo(gitURL string, gitUser string, gitToken string) error {
fs.GitRepo = gitutils.New(gitURL, gitUser, gitToken, fs.RootDir)
return fs.InitializeGitRepo()
}
func (fs *FileSystem) DisableGitRepo() {
fs.GitRepo = nil;
}
func (fs *FileSystem) InitializeGitRepo() error {
if fs.GitRepo == nil {
return errors.New("git settings not configured")
}
return fs.GitRepo.EnsureRepo()
}
func ValidatePath(rootDir, path string) (string, error) {
fullPath := filepath.Join(rootDir, path)
cleanPath := filepath.Clean(fullPath) cleanPath := filepath.Clean(fullPath)
if !strings.HasPrefix(cleanPath, filepath.Clean(rootDir)) { if !strings.HasPrefix(cleanPath, workspacePath) {
return "", fmt.Errorf("invalid path: outside of root directory") return "", fmt.Errorf("invalid path: outside of workspace")
}
relPath, err := filepath.Rel(rootDir, cleanPath)
if err != nil {
return "", err
}
if strings.HasPrefix(relPath, "..") {
return "", fmt.Errorf("invalid path: outside of root directory")
} }
return cleanPath, nil return cleanPath, nil
} }
func (fs *FileSystem) validatePath(path string) (string, error) { // ListFilesRecursively returns a list of all files in the workspace
return ValidatePath(fs.RootDir, path) func ListFilesRecursively(workspace *models.Workspace) ([]FileNode, error) {
workspacePath := GetWorkspacePath(workspace)
return walkDirectory(workspacePath, "")
} }
func (fs *FileSystem) ListFilesRecursively() ([]FileNode, error) { func walkDirectory(dir, prefix string) ([]FileNode, error) {
return fs.walkDirectory(fs.RootDir, "")
}
func (fs *FileSystem) walkDirectory(dir, prefix string) ([]FileNode, error) {
entries, err := os.ReadDir(dir) entries, err := os.ReadDir(dir)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var folders []FileNode var nodes []FileNode
var files []FileNode
for _, entry := range entries { for _, entry := range entries {
name := entry.Name() name := entry.Name()
path := filepath.Join(prefix, name) path := filepath.Join(prefix, name)
fullPath := filepath.Join(dir, name) fullPath := filepath.Join(dir, name)
node := FileNode{
ID: path,
Name: name,
Path: path,
}
if entry.IsDir() { if entry.IsDir() {
children, err := fs.walkDirectory(fullPath, path) children, err := walkDirectory(fullPath, path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
folders = append(folders, FileNode{ node.Children = children
ID: path, // Using path as ID ensures uniqueness
Name: name,
Path: path,
Children: children,
})
} else {
files = append(files, FileNode{
ID: path, // Using path as ID ensures uniqueness
Name: name,
Path: path,
})
} }
nodes = append(nodes, node)
} }
// Sort folders and files alphabetically return nodes, nil
sort.Slice(folders, func(i, j int) bool { return folders[i].Name < folders[j].Name })
sort.Slice(files, func(i, j int) bool { return files[i].Name < files[i].Name })
// Combine folders and files, with folders first
return append(folders, files...), nil
} }
// FindFileByName searches for a file in the workspace by name
func (fs *FileSystem) FindFileByName(filenameOrPath string) ([]string, error) { func FindFileByName(workspace *models.Workspace, filename string) ([]string, error) {
var foundPaths []string var foundPaths []string
var searchPattern string workspacePath := GetWorkspacePath(workspace)
// If no extension is provided, assume .md err := filepath.Walk(workspacePath, func(path string, info os.FileInfo, err error) error {
if !strings.Contains(filenameOrPath, ".") {
searchPattern = filenameOrPath + ".md"
} else {
searchPattern = filenameOrPath
}
err := filepath.Walk(fs.RootDir, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
if !info.IsDir() { if !info.IsDir() {
relPath, err := filepath.Rel(fs.RootDir, path) relPath, err := filepath.Rel(workspacePath, path)
if err != nil { if err != nil {
return err return err
} }
if strings.EqualFold(info.Name(), filename) {
// Check if the file matches the search pattern
if strings.HasSuffix(relPath, searchPattern) ||
strings.EqualFold(info.Name(), searchPattern) {
foundPaths = append(foundPaths, relPath) foundPaths = append(foundPaths, relPath)
} }
} }
@@ -171,16 +101,18 @@ func (fs *FileSystem) FindFileByName(filenameOrPath string) ([]string, error) {
return foundPaths, nil return foundPaths, nil
} }
func (fs *FileSystem) GetFileContent(filePath string) ([]byte, error) { // GetFileContent retrieves the content of a file in the workspace
fullPath, err := fs.validatePath(filePath) func GetFileContent(workspace *models.Workspace, filePath string) ([]byte, error) {
fullPath, err := ValidatePath(workspace, filePath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return os.ReadFile(fullPath) return os.ReadFile(fullPath)
} }
func (fs *FileSystem) SaveFile(filePath string, content []byte) error { // SaveFile saves content to a file in the workspace
fullPath, err := fs.validatePath(filePath) func SaveFile(workspace *models.Workspace, filePath string, content []byte) error {
fullPath, err := ValidatePath(workspace, filePath)
if err != nil { if err != nil {
return err return err
} }
@@ -193,30 +125,17 @@ func (fs *FileSystem) SaveFile(filePath string, content []byte) error {
return os.WriteFile(fullPath, content, 0644) return os.WriteFile(fullPath, content, 0644)
} }
func (fs *FileSystem) DeleteFile(filePath string) error { // DeleteFile removes a file from the workspace
fullPath, err := fs.validatePath(filePath) func DeleteFile(workspace *models.Workspace, filePath string) error {
fullPath, err := ValidatePath(workspace, filePath)
if err != nil { if err != nil {
return err return err
} }
return os.Remove(fullPath) return os.Remove(fullPath)
} }
func (fs *FileSystem) StageCommitAndPush(message string) error { // CreateWorkspaceDirectory creates the directory for a new workspace
if fs.GitRepo == nil { func CreateWorkspaceDirectory(workspace *models.Workspace) error {
return errors.New("git settings not configured") dir := GetWorkspacePath(workspace)
} return os.MkdirAll(dir, 0755)
}
if err := fs.GitRepo.Commit(message); err != nil {
return err
}
return fs.GitRepo.Push()
}
func (fs *FileSystem) Pull() error {
if fs.GitRepo == nil {
return errors.New("git settings not configured")
}
return fs.GitRepo.Pull()
}

View File

@@ -21,9 +21,3 @@ func GetWorkspacePath(workspace *models.Workspace) string {
func GetFilePath(workspace *models.Workspace, relativeFilePath string) string { func GetFilePath(workspace *models.Workspace, relativeFilePath string) string {
return filepath.Join(GetWorkspacePath(workspace), relativeFilePath) return filepath.Join(GetWorkspacePath(workspace), relativeFilePath)
} }
// EnsureWorkspaceDirectory creates the workspace directory if it doesn't exist
func EnsureWorkspaceDirectory(workspace *models.Workspace) error {
dir := GetWorkspacePath(workspace)
return os.MkdirAll(dir, 0755)
}