
Change the package base name of the Go code, from `git.blender.org/flamenco` to `projects.blender.org/studio/flamenco`. The old location, `git.blender.org`, has no longer been use since the [migration to Gitea][1]. The new package names now reflect the actual location where Flamenco is hosted. [1]: https://code.blender.org/2023/02/new-blender-development-infrastructure/
75 lines
2.2 KiB
Go
75 lines
2.2 KiB
Go
package checkout
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/rs/zerolog"
|
|
"projects.blender.org/studio/flamenco/pkg/api"
|
|
"projects.blender.org/studio/flamenco/pkg/shaman/filestore"
|
|
)
|
|
|
|
var (
|
|
ErrMissingFiles = errors.New("unknown files requested in checkout")
|
|
|
|
validCheckoutRegexp = regexp.MustCompile(`^[^/?*:;{}\\][^?*:;{}\\]*$`)
|
|
)
|
|
|
|
// Checkout symlinks the requested files into the checkout directory.
|
|
// Returns the actually-used checkout directory, relative to the configured checkout root.
|
|
func (m *Manager) Checkout(ctx context.Context, checkout api.ShamanCheckout) (string, error) {
|
|
logger := (*zerolog.Ctx(ctx))
|
|
logger.Debug().
|
|
Str("checkoutPath", checkout.CheckoutPath).
|
|
Msg("shaman: user requested checkout creation")
|
|
|
|
// Actually create the checkout.
|
|
resolvedCheckoutInfo, err := m.PrepareCheckout(checkout.CheckoutPath)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
logger = logger.With().Str("checkoutPath", resolvedCheckoutInfo.RelativePath).Logger()
|
|
|
|
// The checkout directory was created, so if anything fails now, it should be erased.
|
|
var checkoutOK bool
|
|
defer func() {
|
|
if !checkoutOK {
|
|
err := m.EraseCheckout(checkout.CheckoutPath)
|
|
if err != nil {
|
|
logger.Error().Err(err).Msg("shaman: error erasing checkout directory")
|
|
}
|
|
}
|
|
}()
|
|
|
|
for _, fileSpec := range checkout.Files {
|
|
blobPath, status := m.fileStore.ResolveFile(fileSpec.Sha, int64(fileSpec.Size), filestore.ResolveStoredOnly)
|
|
if status != filestore.StatusStored {
|
|
// Caller should upload this file before we can create the checkout.
|
|
return "", ErrMissingFiles
|
|
}
|
|
|
|
if err := m.SymlinkToCheckout(blobPath, resolvedCheckoutInfo.absolutePath, fileSpec.Path); err != nil {
|
|
return "", fmt.Errorf("symlinking %q to checkout: %w", fileSpec.Path, err)
|
|
}
|
|
}
|
|
|
|
checkoutOK = true // Prevent the checkout directory from being erased again.
|
|
logger.Info().Msg("shaman: checkout created")
|
|
return resolvedCheckoutInfo.RelativePath, nil
|
|
}
|
|
|
|
func isValidCheckoutPath(checkoutPath string) bool {
|
|
if !validCheckoutRegexp.MatchString(checkoutPath) {
|
|
return false
|
|
}
|
|
if strings.Contains(checkoutPath, "../") || strings.Contains(checkoutPath, "/..") {
|
|
return false
|
|
}
|
|
return true
|
|
}
|