Refactor web build process and update documentation
- Removed Node.js build artifacts from .gitignore and adjusted Makefile to reflect changes in web UI build process, now using server-rendered Go templates instead of React. - Updated README to clarify the new web UI architecture and output formats, emphasizing the removal of the Node.js build step. - Added a command to set the number of frames per render task in manager configuration, enhancing user control over rendering settings. - Improved Gitea workflow by removing unnecessary npm install step, streamlining the CI process.
This commit is contained in:
@@ -60,7 +60,7 @@ func (s *Storage) TempDir(pattern string) (string, error) {
|
||||
if err := os.MkdirAll(s.tempPath(), 0755); err != nil {
|
||||
return "", fmt.Errorf("failed to create temp directory: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Create temp directory under storage base path
|
||||
return os.MkdirTemp(s.tempPath(), pattern)
|
||||
}
|
||||
@@ -166,12 +166,12 @@ func (s *Storage) GetFileSize(filePath string) (int64, error) {
|
||||
// Returns a list of all extracted file paths
|
||||
func (s *Storage) ExtractZip(zipPath, destDir string) ([]string, error) {
|
||||
log.Printf("Extracting ZIP archive: %s -> %s", zipPath, destDir)
|
||||
|
||||
|
||||
// Ensure destination directory exists
|
||||
if err := os.MkdirAll(destDir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create destination directory: %w", err)
|
||||
}
|
||||
|
||||
|
||||
r, err := zip.OpenReader(zipPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open ZIP file: %w", err)
|
||||
@@ -187,7 +187,7 @@ func (s *Storage) ExtractZip(zipPath, destDir string) ([]string, error) {
|
||||
for _, f := range r.File {
|
||||
// Sanitize file path to prevent directory traversal
|
||||
destPath := filepath.Join(destDir, f.Name)
|
||||
|
||||
|
||||
cleanDestPath := filepath.Clean(destPath)
|
||||
cleanDestDir := filepath.Clean(destDir)
|
||||
if !strings.HasPrefix(cleanDestPath, cleanDestDir+string(os.PathSeparator)) && cleanDestPath != cleanDestDir {
|
||||
@@ -520,7 +520,7 @@ func (s *Storage) CreateJobContextFromDir(sourceDir string, jobID int64, exclude
|
||||
if commonPrefix != "" && strings.HasPrefix(tarPath, commonPrefix) {
|
||||
tarPath = strings.TrimPrefix(tarPath, commonPrefix)
|
||||
}
|
||||
|
||||
|
||||
// Check if it's a .blend file at root (no path separators after prefix stripping)
|
||||
if strings.HasSuffix(strings.ToLower(tarPath), ".blend") {
|
||||
// Check if it's at root level (no directory separators)
|
||||
@@ -566,7 +566,7 @@ func (s *Storage) CreateJobContextFromDir(sourceDir string, jobID int64, exclude
|
||||
// Get relative path and strip common prefix if present
|
||||
relPath := relPaths[i]
|
||||
tarPath := filepath.ToSlash(relPath)
|
||||
|
||||
|
||||
// Strip common prefix if found
|
||||
if commonPrefix != "" && strings.HasPrefix(tarPath, commonPrefix) {
|
||||
tarPath = strings.TrimPrefix(tarPath, commonPrefix)
|
||||
@@ -608,3 +608,129 @@ func (s *Storage) CreateJobContextFromDir(sourceDir string, jobID int64, exclude
|
||||
return contextPath, nil
|
||||
}
|
||||
|
||||
// CreateContextArchiveFromDirToPath creates a context archive from files in sourceDir at destPath.
|
||||
// This is used for pre-job upload sessions where the archive is staged before a job ID exists.
|
||||
func (s *Storage) CreateContextArchiveFromDirToPath(sourceDir, destPath string, excludeFiles ...string) (string, error) {
|
||||
excludeSet := make(map[string]bool)
|
||||
for _, excludeFile := range excludeFiles {
|
||||
excludePath := filepath.Clean(excludeFile)
|
||||
excludeSet[excludePath] = true
|
||||
excludeSet[filepath.ToSlash(excludePath)] = true
|
||||
}
|
||||
|
||||
var filesToInclude []string
|
||||
err := filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if isBlenderSaveFile(info.Name()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
relPath, err := filepath.Rel(sourceDir, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cleanRelPath := filepath.Clean(relPath)
|
||||
if strings.HasPrefix(cleanRelPath, "..") {
|
||||
return fmt.Errorf("invalid file path: %s", relPath)
|
||||
}
|
||||
if excludeSet[cleanRelPath] || excludeSet[filepath.ToSlash(cleanRelPath)] {
|
||||
return nil
|
||||
}
|
||||
|
||||
filesToInclude = append(filesToInclude, path)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to walk source directory: %w", err)
|
||||
}
|
||||
if len(filesToInclude) == 0 {
|
||||
return "", fmt.Errorf("no files found to include in context archive")
|
||||
}
|
||||
|
||||
relPaths := make([]string, 0, len(filesToInclude))
|
||||
for _, filePath := range filesToInclude {
|
||||
relPath, err := filepath.Rel(sourceDir, filePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get relative path: %w", err)
|
||||
}
|
||||
relPaths = append(relPaths, relPath)
|
||||
}
|
||||
|
||||
commonPrefix := findCommonPrefix(relPaths)
|
||||
blendFilesAtRoot := 0
|
||||
for _, relPath := range relPaths {
|
||||
tarPath := filepath.ToSlash(relPath)
|
||||
if commonPrefix != "" && strings.HasPrefix(tarPath, commonPrefix) {
|
||||
tarPath = strings.TrimPrefix(tarPath, commonPrefix)
|
||||
}
|
||||
if strings.HasSuffix(strings.ToLower(tarPath), ".blend") && !strings.Contains(tarPath, "/") {
|
||||
blendFilesAtRoot++
|
||||
}
|
||||
}
|
||||
if blendFilesAtRoot == 0 {
|
||||
return "", fmt.Errorf("no .blend file found at root level in context archive - .blend files must be at the root level of the uploaded archive, not in subdirectories")
|
||||
}
|
||||
if blendFilesAtRoot > 1 {
|
||||
return "", fmt.Errorf("multiple .blend files found at root level in context archive (found %d, expected 1)", blendFilesAtRoot)
|
||||
}
|
||||
|
||||
contextFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create context file: %w", err)
|
||||
}
|
||||
defer contextFile.Close()
|
||||
|
||||
tarWriter := tar.NewWriter(contextFile)
|
||||
defer tarWriter.Close()
|
||||
copyBuf := make([]byte, 32*1024)
|
||||
|
||||
for i, filePath := range filesToInclude {
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to open file: %w", err)
|
||||
}
|
||||
|
||||
info, err := file.Stat()
|
||||
if err != nil {
|
||||
file.Close()
|
||||
return "", fmt.Errorf("failed to stat file: %w", err)
|
||||
}
|
||||
|
||||
tarPath := filepath.ToSlash(relPaths[i])
|
||||
if commonPrefix != "" && strings.HasPrefix(tarPath, commonPrefix) {
|
||||
tarPath = strings.TrimPrefix(tarPath, commonPrefix)
|
||||
}
|
||||
|
||||
header, err := tar.FileInfoHeader(info, "")
|
||||
if err != nil {
|
||||
file.Close()
|
||||
return "", fmt.Errorf("failed to create tar header: %w", err)
|
||||
}
|
||||
header.Name = tarPath
|
||||
|
||||
if err := tarWriter.WriteHeader(header); err != nil {
|
||||
file.Close()
|
||||
return "", fmt.Errorf("failed to write tar header: %w", err)
|
||||
}
|
||||
|
||||
if _, err := io.CopyBuffer(tarWriter, file, copyBuf); err != nil {
|
||||
file.Close()
|
||||
return "", fmt.Errorf("failed to write file to tar: %w", err)
|
||||
}
|
||||
file.Close()
|
||||
}
|
||||
|
||||
if err := tarWriter.Close(); err != nil {
|
||||
return "", fmt.Errorf("failed to close tar writer: %w", err)
|
||||
}
|
||||
if err := contextFile.Close(); err != nil {
|
||||
return "", fmt.Errorf("failed to close context file: %w", err)
|
||||
}
|
||||
|
||||
return destPath, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user