mirror of
https://github.com/crawlab-team/crawlab.git
synced 2026-01-21 17:21:09 +01:00
194 lines
4.6 KiB
Go
194 lines
4.6 KiB
Go
package fs
|
|
|
|
import (
|
|
"github.com/crawlab-team/crawlab/core/entity"
|
|
"github.com/crawlab-team/crawlab/core/interfaces"
|
|
"github.com/crawlab-team/crawlab/core/utils"
|
|
"github.com/google/uuid"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
type Service struct {
|
|
// settings
|
|
rootPath string
|
|
skipNames []string
|
|
|
|
// internals
|
|
interfaces.Logger
|
|
}
|
|
|
|
func (svc *Service) List(path string) (files []entity.FsFileInfo, err error) {
|
|
// Normalize the provided path
|
|
normPath := filepath.Clean(path)
|
|
if normPath == "." {
|
|
normPath = ""
|
|
}
|
|
fullPath := filepath.Join(svc.rootPath, normPath)
|
|
|
|
// Temporary map to hold directory information and their children
|
|
dirMap := make(map[string]*entity.FsFileInfo)
|
|
|
|
// Use filepath.Walk to recursively traverse directories
|
|
err = filepath.Walk(fullPath, func(p string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
svc.Errorf("failed to walk path: %v", err)
|
|
return err
|
|
}
|
|
|
|
relPath, err := filepath.Rel(svc.rootPath, p)
|
|
if err != nil {
|
|
svc.Errorf("failed to get relative path: %v", err)
|
|
return err
|
|
}
|
|
|
|
fi := &entity.FsFileInfo{
|
|
Name: info.Name(),
|
|
Path: filepath.ToSlash(relPath),
|
|
FullPath: p,
|
|
Extension: filepath.Ext(p),
|
|
IsDir: info.IsDir(),
|
|
FileSize: info.Size(),
|
|
ModTime: info.ModTime(),
|
|
Mode: info.Mode(),
|
|
Children: nil,
|
|
}
|
|
|
|
// Skip files/folders matching the pattern
|
|
for _, name := range svc.skipNames {
|
|
if fi.Name == name {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if info.IsDir() {
|
|
dirMap[p] = fi
|
|
}
|
|
|
|
if parentDir := filepath.Dir(p); parentDir != p && dirMap[parentDir] != nil {
|
|
dirMap[parentDir].Children = append(dirMap[parentDir].Children, fi)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if rootInfo, ok := dirMap[fullPath]; ok {
|
|
for _, info := range rootInfo.Children {
|
|
files = append(files, *info)
|
|
}
|
|
}
|
|
|
|
return files, err
|
|
}
|
|
|
|
func (svc *Service) GetFile(path string) (data []byte, err error) {
|
|
return os.ReadFile(filepath.Join(svc.rootPath, path))
|
|
}
|
|
|
|
func (svc *Service) GetFileInfo(path string) (file *entity.FsFileInfo, err error) {
|
|
f, err := os.Stat(filepath.Join(svc.rootPath, path))
|
|
if err != nil {
|
|
svc.Errorf("failed to get file info: %v", err)
|
|
return nil, err
|
|
}
|
|
return &entity.FsFileInfo{
|
|
Name: f.Name(),
|
|
Path: path,
|
|
FullPath: filepath.Join(svc.rootPath, path),
|
|
Extension: filepath.Ext(path),
|
|
IsDir: f.IsDir(),
|
|
FileSize: f.Size(),
|
|
ModTime: f.ModTime(),
|
|
Mode: f.Mode(),
|
|
Children: nil,
|
|
}, nil
|
|
}
|
|
|
|
func (svc *Service) Save(path string, data []byte) (err error) {
|
|
// Create directories if not exist
|
|
dir := filepath.Dir(filepath.Join(svc.rootPath, path))
|
|
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
svc.Errorf("failed to create directory: %v", err)
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Write file
|
|
return os.WriteFile(filepath.Join(svc.rootPath, path), data, 0644)
|
|
}
|
|
|
|
func (svc *Service) CreateDir(path string) (err error) {
|
|
return os.MkdirAll(filepath.Join(svc.rootPath, path), 0755)
|
|
}
|
|
|
|
func (svc *Service) Rename(path, newPath string) (err error) {
|
|
oldPath := filepath.Join(svc.rootPath, path)
|
|
newFullPath := filepath.Join(svc.rootPath, newPath)
|
|
return os.Rename(oldPath, newFullPath)
|
|
}
|
|
|
|
func (svc *Service) Delete(path string) (err error) {
|
|
fullPath := filepath.Join(svc.rootPath, path)
|
|
return os.RemoveAll(fullPath)
|
|
}
|
|
|
|
func (svc *Service) Copy(path, newPath string) (err error) {
|
|
srcPath := filepath.Join(svc.rootPath, path)
|
|
destPath := filepath.Join(svc.rootPath, newPath)
|
|
|
|
// Get source info
|
|
srcInfo, err := os.Stat(srcPath)
|
|
if err != nil {
|
|
svc.Errorf("failed to get source info: %v", err)
|
|
return err
|
|
}
|
|
|
|
// If source is file, copy it
|
|
if !srcInfo.IsDir() {
|
|
srcFile, err := os.Open(srcPath)
|
|
if err != nil {
|
|
svc.Errorf("failed to open source file: %v", err)
|
|
return err
|
|
}
|
|
defer srcFile.Close()
|
|
|
|
destFile, err := os.Create(destPath)
|
|
if err != nil {
|
|
svc.Errorf("failed to create destination file: %v", err)
|
|
return err
|
|
}
|
|
defer destFile.Close()
|
|
|
|
_, err = io.Copy(destFile, srcFile)
|
|
if err != nil {
|
|
svc.Errorf("failed to copy file: %v", err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
} else {
|
|
// If source is directory, copy it recursively
|
|
return utils.CopyDir(srcPath, destPath)
|
|
}
|
|
}
|
|
|
|
func (svc *Service) Export() (resultPath string, err error) {
|
|
zipFilePath := filepath.Join(os.TempDir(), uuid.New().String()+".zip")
|
|
if err := utils.ZipDirectory(svc.rootPath, zipFilePath); err != nil {
|
|
svc.Errorf("failed to zip directory: %v", err)
|
|
return "", err
|
|
}
|
|
|
|
return zipFilePath, nil
|
|
}
|
|
|
|
func NewFsService(path string) (svc *Service) {
|
|
return &Service{
|
|
rootPath: path,
|
|
skipNames: []string{".git"},
|
|
Logger: utils.NewLogger("FsService"),
|
|
}
|
|
}
|