From 9688b2d5284b06a79ab91fdfaffd61549146e9f8 Mon Sep 17 00:00:00 2001 From: LordMathis Date: Sat, 9 Nov 2024 21:59:04 +0100 Subject: [PATCH] Split filesystem.go file --- backend/internal/filesystem/files.go | 153 +++++++++++++++ backend/internal/filesystem/filesystem.go | 220 +--------------------- backend/internal/filesystem/git.go | 60 ++++++ backend/internal/filesystem/workspace.go | 40 ++++ 4 files changed, 256 insertions(+), 217 deletions(-) create mode 100644 backend/internal/filesystem/files.go create mode 100644 backend/internal/filesystem/git.go create mode 100644 backend/internal/filesystem/workspace.go diff --git a/backend/internal/filesystem/files.go b/backend/internal/filesystem/files.go new file mode 100644 index 0000000..152e284 --- /dev/null +++ b/backend/internal/filesystem/files.go @@ -0,0 +1,153 @@ +// Package filesystem provides functionalities to interact with the file system, +// including listing files, finding files by name, getting file content, saving files, and deleting files. +package filesystem + +import ( + "errors" + "os" + "path/filepath" + "sort" + "strings" +) + +// FileNode represents a file or directory in the file system. +type FileNode struct { + ID string `json:"id"` + Name string `json:"name"` + Path string `json:"path"` + Children []FileNode `json:"children,omitempty"` +} + +// ListFilesRecursively returns a list of all files in the workspace directory and its subdirectories. +func (fs *FileSystem) ListFilesRecursively(userID, workspaceID int) ([]FileNode, error) { + workspacePath := fs.GetWorkspacePath(userID, workspaceID) + return fs.walkDirectory(workspacePath, "") +} + +func (fs *FileSystem) walkDirectory(dir, prefix string) ([]FileNode, error) { + entries, err := os.ReadDir(dir) + if err != nil { + return nil, err + } + + // Split entries into directories and files + var dirs, files []os.DirEntry + for _, entry := range entries { + if entry.IsDir() { + dirs = append(dirs, entry) + } else { + files = append(files, entry) + } + } + + // Sort directories and files separately + sort.Slice(dirs, func(i, j int) bool { + return strings.ToLower(dirs[i].Name()) < strings.ToLower(dirs[j].Name()) + }) + sort.Slice(files, func(i, j int) bool { + return strings.ToLower(files[i].Name()) < strings.ToLower(files[j].Name()) + }) + + // Create combined slice with directories first, then files + nodes := make([]FileNode, 0, len(entries)) + + // Add directories first + for _, entry := range dirs { + name := entry.Name() + path := filepath.Join(prefix, name) + fullPath := filepath.Join(dir, name) + + children, err := fs.walkDirectory(fullPath, path) + if err != nil { + return nil, err + } + + node := FileNode{ + ID: path, + Name: name, + Path: path, + Children: children, + } + nodes = append(nodes, node) + } + + // Then add files + for _, entry := range files { + name := entry.Name() + path := filepath.Join(prefix, name) + + node := FileNode{ + ID: path, + Name: name, + Path: path, + } + nodes = append(nodes, node) + } + + return nodes, nil +} + +// FindFileByName returns a list of file paths that match the given filename. +func (fs *FileSystem) FindFileByName(userID, workspaceID int, filename string) ([]string, error) { + var foundPaths []string + workspacePath := fs.GetWorkspacePath(userID, workspaceID) + + err := filepath.Walk(workspacePath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + relPath, err := filepath.Rel(workspacePath, path) + if err != nil { + return err + } + if strings.EqualFold(info.Name(), filename) { + foundPaths = append(foundPaths, relPath) + } + } + return nil + }) + + if err != nil { + return nil, err + } + + if len(foundPaths) == 0 { + return nil, errors.New("file not found") + } + + return foundPaths, nil +} + +// GetFileContent returns the content of the file at the given path. +func (fs *FileSystem) GetFileContent(userID, workspaceID int, filePath string) ([]byte, error) { + fullPath, err := fs.ValidatePath(userID, workspaceID, filePath) + if err != nil { + return nil, err + } + return os.ReadFile(fullPath) +} + +// SaveFile writes the content to the file at the given path. +func (fs *FileSystem) SaveFile(userID, workspaceID int, filePath string, content []byte) error { + fullPath, err := fs.ValidatePath(userID, workspaceID, filePath) + if err != nil { + return err + } + + dir := filepath.Dir(fullPath) + if err := os.MkdirAll(dir, 0755); err != nil { + return err + } + + return os.WriteFile(fullPath, content, 0644) +} + +// DeleteFile deletes the file at the given path. +func (fs *FileSystem) DeleteFile(userID, workspaceID int, filePath string) error { + fullPath, err := fs.ValidatePath(userID, workspaceID, filePath) + if err != nil { + return err + } + return os.Remove(fullPath) +} diff --git a/backend/internal/filesystem/filesystem.go b/backend/internal/filesystem/filesystem.go index 38e29c1..87ba6b2 100644 --- a/backend/internal/filesystem/filesystem.go +++ b/backend/internal/filesystem/filesystem.go @@ -1,27 +1,19 @@ package filesystem import ( - "errors" "fmt" "novamd/internal/gitutils" - "os" "path/filepath" - "sort" "strings" ) +// FileSystem represents the file system structure. type FileSystem struct { RootDir string GitRepos map[int]map[int]*gitutils.GitRepo // map[userID]map[workspaceID]*gitutils.GitRepo } -type FileNode struct { - ID string `json:"id"` - Name string `json:"name"` - Path string `json:"path"` - Children []FileNode `json:"children,omitempty"` -} - +// New creates a new FileSystem instance. func New(rootDir string) *FileSystem { return &FileSystem{ RootDir: rootDir, @@ -29,30 +21,7 @@ func New(rootDir string) *FileSystem { } } -func (fs *FileSystem) GetWorkspacePath(userID, workspaceID int) string { - return filepath.Join(fs.RootDir, fmt.Sprintf("%d", userID), fmt.Sprintf("%d", workspaceID)) -} - -func (fs *FileSystem) InitializeUserWorkspace(userID, workspaceID int) error { - workspacePath := fs.GetWorkspacePath(userID, workspaceID) - err := os.MkdirAll(workspacePath, 0755) - if err != nil { - return fmt.Errorf("failed to create workspace directory: %w", err) - } - - return nil -} - -func (fs *FileSystem) DeleteUserWorkspace(userID, workspaceID int) error { - workspacePath := fs.GetWorkspacePath(userID, workspaceID) - err := os.RemoveAll(workspacePath) - if err != nil { - return fmt.Errorf("failed to delete workspace directory: %w", err) - } - - return nil -} - +// ValidatePath validates the given path and returns the cleaned path if it is valid. func (fs *FileSystem) ValidatePath(userID, workspaceID int, path string) (string, error) { workspacePath := fs.GetWorkspacePath(userID, workspaceID) fullPath := filepath.Join(workspacePath, path) @@ -64,186 +33,3 @@ func (fs *FileSystem) ValidatePath(userID, workspaceID int, path string) (string return cleanPath, nil } - -func (fs *FileSystem) ListFilesRecursively(userID, workspaceID int) ([]FileNode, error) { - workspacePath := fs.GetWorkspacePath(userID, workspaceID) - return fs.walkDirectory(workspacePath, "") -} - -func (fs *FileSystem) walkDirectory(dir, prefix string) ([]FileNode, error) { - entries, err := os.ReadDir(dir) - if err != nil { - return nil, err - } - - // Split entries into directories and files - var dirs, files []os.DirEntry - for _, entry := range entries { - if entry.IsDir() { - dirs = append(dirs, entry) - } else { - files = append(files, entry) - } - } - - // Sort directories and files separately - sort.Slice(dirs, func(i, j int) bool { - return strings.ToLower(dirs[i].Name()) < strings.ToLower(dirs[j].Name()) - }) - sort.Slice(files, func(i, j int) bool { - return strings.ToLower(files[i].Name()) < strings.ToLower(files[j].Name()) - }) - - // Create combined slice with directories first, then files - nodes := make([]FileNode, 0, len(entries)) - - // Add directories first - for _, entry := range dirs { - name := entry.Name() - path := filepath.Join(prefix, name) - fullPath := filepath.Join(dir, name) - - children, err := fs.walkDirectory(fullPath, path) - if err != nil { - return nil, err - } - - node := FileNode{ - ID: path, - Name: name, - Path: path, - Children: children, - } - nodes = append(nodes, node) - } - - // Then add files - for _, entry := range files { - name := entry.Name() - path := filepath.Join(prefix, name) - - node := FileNode{ - ID: path, - Name: name, - Path: path, - } - nodes = append(nodes, node) - } - - return nodes, nil -} - -func (fs *FileSystem) FindFileByName(userID, workspaceID int, filename string) ([]string, error) { - var foundPaths []string - workspacePath := fs.GetWorkspacePath(userID, workspaceID) - - err := filepath.Walk(workspacePath, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() { - relPath, err := filepath.Rel(workspacePath, path) - if err != nil { - return err - } - if strings.EqualFold(info.Name(), filename) { - foundPaths = append(foundPaths, relPath) - } - } - return nil - }) - - if err != nil { - return nil, err - } - - if len(foundPaths) == 0 { - return nil, errors.New("file not found") - } - - return foundPaths, nil -} - -func (fs *FileSystem) GetFileContent(userID, workspaceID int, filePath string) ([]byte, error) { - fullPath, err := fs.ValidatePath(userID, workspaceID, filePath) - if err != nil { - return nil, err - } - return os.ReadFile(fullPath) -} - -func (fs *FileSystem) SaveFile(userID, workspaceID int, filePath string, content []byte) error { - fullPath, err := fs.ValidatePath(userID, workspaceID, filePath) - if err != nil { - return err - } - - dir := filepath.Dir(fullPath) - if err := os.MkdirAll(dir, 0755); err != nil { - return err - } - - return os.WriteFile(fullPath, content, 0644) -} - -func (fs *FileSystem) DeleteFile(userID, workspaceID int, filePath string) error { - fullPath, err := fs.ValidatePath(userID, workspaceID, filePath) - if err != nil { - return err - } - return os.Remove(fullPath) -} - -func (fs *FileSystem) CreateWorkspaceDirectory(userID, workspaceID int) error { - dir := fs.GetWorkspacePath(userID, workspaceID) - return os.MkdirAll(dir, 0755) -} - -func (fs *FileSystem) SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToken string) error { - workspacePath := fs.GetWorkspacePath(userID, workspaceID) - if _, ok := fs.GitRepos[userID]; !ok { - fs.GitRepos[userID] = make(map[int]*gitutils.GitRepo) - } - fs.GitRepos[userID][workspaceID] = gitutils.New(gitURL, gitUser, gitToken, workspacePath) - return fs.GitRepos[userID][workspaceID].EnsureRepo() -} - -func (fs *FileSystem) DisableGitRepo(userID, workspaceID int) { - if userRepos, ok := fs.GitRepos[userID]; ok { - delete(userRepos, workspaceID) - if len(userRepos) == 0 { - delete(fs.GitRepos, userID) - } - } -} - -func (fs *FileSystem) StageCommitAndPush(userID, workspaceID int, message string) error { - repo, ok := fs.getGitRepo(userID, workspaceID) - if !ok { - return errors.New("git settings not configured for this workspace") - } - - if err := repo.Commit(message); err != nil { - return err - } - - return repo.Push() -} - -func (fs *FileSystem) Pull(userID, workspaceID int) error { - repo, ok := fs.getGitRepo(userID, workspaceID) - if !ok { - return errors.New("git settings not configured for this workspace") - } - - return repo.Pull() -} - -func (fs *FileSystem) getGitRepo(userID, workspaceID int) (*gitutils.GitRepo, bool) { - userRepos, ok := fs.GitRepos[userID] - if !ok { - return nil, false - } - repo, ok := userRepos[workspaceID] - return repo, ok -} diff --git a/backend/internal/filesystem/git.go b/backend/internal/filesystem/git.go new file mode 100644 index 0000000..6c97a6f --- /dev/null +++ b/backend/internal/filesystem/git.go @@ -0,0 +1,60 @@ +package filesystem + +import ( + "errors" + "novamd/internal/gitutils" +) + +// SetupGitRepo sets up a Git repository for the given user and workspace IDs. +func (fs *FileSystem) SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToken string) error { + workspacePath := fs.GetWorkspacePath(userID, workspaceID) + if _, ok := fs.GitRepos[userID]; !ok { + fs.GitRepos[userID] = make(map[int]*gitutils.GitRepo) + } + fs.GitRepos[userID][workspaceID] = gitutils.New(gitURL, gitUser, gitToken, workspacePath) + return fs.GitRepos[userID][workspaceID].EnsureRepo() +} + +// DisableGitRepo disables the Git repository for the given user and workspace IDs. +func (fs *FileSystem) DisableGitRepo(userID, workspaceID int) { + if userRepos, ok := fs.GitRepos[userID]; ok { + delete(userRepos, workspaceID) + if len(userRepos) == 0 { + delete(fs.GitRepos, userID) + } + } +} + +// StageCommitAndPush stages, commits, and pushes the changes to the Git repository. +func (fs *FileSystem) StageCommitAndPush(userID, workspaceID int, message string) error { + repo, ok := fs.getGitRepo(userID, workspaceID) + if !ok { + return errors.New("git settings not configured for this workspace") + } + + if err := repo.Commit(message); err != nil { + return err + } + + return repo.Push() +} + +// Pull pulls the changes from the remote Git repository. +func (fs *FileSystem) Pull(userID, workspaceID int) error { + repo, ok := fs.getGitRepo(userID, workspaceID) + if !ok { + return errors.New("git settings not configured for this workspace") + } + + return repo.Pull() +} + +// getGitRepo returns the Git repository for the given user and workspace IDs. +func (fs *FileSystem) getGitRepo(userID, workspaceID int) (*gitutils.GitRepo, bool) { + userRepos, ok := fs.GitRepos[userID] + if !ok { + return nil, false + } + repo, ok := userRepos[workspaceID] + return repo, ok +} diff --git a/backend/internal/filesystem/workspace.go b/backend/internal/filesystem/workspace.go new file mode 100644 index 0000000..122c816 --- /dev/null +++ b/backend/internal/filesystem/workspace.go @@ -0,0 +1,40 @@ +package filesystem + +import ( + "fmt" + "os" + "path/filepath" +) + +// GetWorkspacePath returns the path to the workspace directory for the given user and workspace IDs. +func (fs *FileSystem) GetWorkspacePath(userID, workspaceID int) string { + return filepath.Join(fs.RootDir, fmt.Sprintf("%d", userID), fmt.Sprintf("%d", workspaceID)) +} + +// InitializeUserWorkspace creates the workspace directory for the given user and workspace IDs. +func (fs *FileSystem) InitializeUserWorkspace(userID, workspaceID int) error { + workspacePath := fs.GetWorkspacePath(userID, workspaceID) + err := os.MkdirAll(workspacePath, 0755) + if err != nil { + return fmt.Errorf("failed to create workspace directory: %w", err) + } + + return nil +} + +// DeleteUserWorkspace deletes the workspace directory for the given user and workspace IDs. +func (fs *FileSystem) DeleteUserWorkspace(userID, workspaceID int) error { + workspacePath := fs.GetWorkspacePath(userID, workspaceID) + err := os.RemoveAll(workspacePath) + if err != nil { + return fmt.Errorf("failed to delete workspace directory: %w", err) + } + + return nil +} + +// CreateWorkspaceDirectory creates the workspace directory for the given user and workspace IDs. +func (fs *FileSystem) CreateWorkspaceDirectory(userID, workspaceID int) error { + dir := fs.GetWorkspacePath(userID, workspaceID) + return os.MkdirAll(dir, 0755) +}