0003_migrate_lfs_objects.go

 1package migrate
 2
 3import (
 4	"context"
 5	"os"
 6	"path/filepath"
 7	"strconv"
 8
 9	"github.com/charmbracelet/log/v2"
10	"github.com/charmbracelet/soft-serve/pkg/config"
11	"github.com/charmbracelet/soft-serve/pkg/db"
12	"github.com/charmbracelet/soft-serve/pkg/db/models"
13)
14
15const (
16	migrateLfsObjectsName    = "migrate_lfs_objects"
17	migrateLfsObjectsVersion = 3
18)
19
20// Correct LFS objects relative path.
21// From OID[:2]/OID[2:4]/OID[4:] to OID[:2]/OID[2:4]/OID
22// See: https://github.com/git-lfs/git-lfs/blob/main/docs/spec.md#intercepting-git
23var migrateLfsObjects = Migration{
24	Name:    migrateLfsObjectsName,
25	Version: migrateLfsObjectsVersion,
26	Migrate: func(ctx context.Context, tx *db.Tx) error {
27		cfg := config.FromContext(ctx)
28		logger := log.FromContext(ctx).WithPrefix("migrate_lfs_objects")
29
30		var repoIDs []int64
31		if err := tx.Select(&repoIDs, "SELECT id FROM repos"); err != nil {
32			return err //nolint:wrapcheck
33		}
34		for _, r := range repoIDs {
35			var objs []models.LFSObject
36			if err := tx.Select(&objs, "SELECT * FROM lfs_objects WHERE repo_id = ?", r); err != nil {
37				return err //nolint:wrapcheck
38			}
39			objsp := filepath.Join(cfg.DataPath, "lfs", strconv.FormatInt(r, 10), "objects")
40			for _, obj := range objs {
41				oldpath := filepath.Join(objsp, badRelativePath(obj.Oid))
42				newpath := filepath.Join(objsp, goodRelativePath(obj.Oid))
43				if _, err := os.Stat(oldpath); err == nil {
44					if err := os.Rename(oldpath, newpath); err != nil {
45						logger.Error("rename lfs object", "oldpath", oldpath, "newpath", newpath, "err", err)
46						continue
47					}
48				}
49			}
50		}
51		return nil
52	},
53	Rollback: func(context.Context, *db.Tx) error {
54		return nil
55	},
56}
57
58func goodRelativePath(oid string) string {
59	if len(oid) < 5 {
60		return oid
61	}
62	return filepath.Join(oid[:2], oid[2:4], oid)
63}
64
65func badRelativePath(oid string) string {
66	if len(oid) < 5 {
67		return oid
68	}
69	return filepath.Join(oid[:2], oid[2:4], oid[4:])
70}