mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-06 07:54:22 +00:00
Update fs for workspaces
This commit is contained in:
@@ -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()
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user