chore: improve resource internal_path migrator (#2698)

* chore: improve internal path migrator
- handle mixed path styles
- handle Windows paths
- add tests

* chore: fix goimports error
pull/2699/head
Lincoln Nogueira 1 year ago committed by GitHub
parent 914c0620c4
commit 369b8af109
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -59,11 +59,14 @@ var (
} }
store := store.New(dbDriver, profile) store := store.New(dbDriver, profile)
go func() {
if err := store.MigrateResourceInternalPath(ctx); err != nil { if err := store.MigrateResourceInternalPath(ctx); err != nil {
cancel() cancel()
log.Error("failed to migrate resource internal path", zap.Error(err)) log.Error("failed to migrate resource internal path", zap.Error(err))
return return
} }
}()
s, err := server.NewServer(ctx, profile, store) s, err := server.NewServer(ctx, profile, store)
if err != nil { if err != nil {

@ -2,10 +2,15 @@ package store
import ( import (
"context" "context"
"path/filepath" "fmt"
"os"
"time"
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/usememos/memos/internal/log"
) )
// MigrateResourceInternalPath migrates resource internal path from absolute path to relative path. // MigrateResourceInternalPath migrates resource internal path from absolute path to relative path.
@ -15,30 +20,37 @@ func (s *Store) MigrateResourceInternalPath(ctx context.Context) error {
return errors.Wrap(err, "failed to list resources") return errors.Wrap(err, "failed to list resources")
} }
dataPath := strings.ReplaceAll(s.Profile.Data, `\`, "/")
migrateStartTime := time.Now()
migratedCount := 0
for _, resource := range resources { for _, resource := range resources {
if resource.InternalPath == "" { if resource.InternalPath == "" {
continue continue
} }
internalPath := resource.InternalPath internalPath := strings.ReplaceAll(resource.InternalPath, `\`, "/")
if filepath.IsAbs(internalPath) { if !strings.HasPrefix(internalPath, dataPath) {
if !strings.HasPrefix(internalPath, s.Profile.Data) {
// Invalid internal path, skip.
continue continue
} }
internalPath = strings.TrimPrefix(internalPath, s.Profile.Data)
for strings.HasPrefix(internalPath, "/") { internalPath = strings.TrimPrefix(internalPath, dataPath)
internalPath = strings.TrimPrefix(internalPath, "/")
for os.IsPathSeparator(internalPath[0]) {
internalPath = internalPath[1:]
} }
_, err := s.UpdateResource(ctx, &UpdateResource{ _, err := s.UpdateResource(ctx, &UpdateResource{
ID: resource.ID, ID: resource.ID,
InternalPath: &internalPath, InternalPath: &internalPath,
}) })
if err != nil { if err != nil {
return errors.Wrap(err, "failed to update resource") return errors.Wrap(err, "failed to update local resource path")
}
} }
migratedCount++
} }
if migratedCount > 0 {
log.Info(fmt.Sprintf("migrated %d local resource paths in %s", migratedCount, time.Since(migrateStartTime)))
}
return nil return nil
} }

@ -0,0 +1,56 @@
package teststore
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/usememos/memos/store"
)
func TestMigrateResourceInternalPath(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
testCases := []map[string]string{
{
ts.Profile.Data + "/assets/test.jpg": "assets/test.jpg",
},
{
ts.Profile.Data + `\assets\test.jpg`: "assets/test.jpg",
},
{
"/unhandled/path/test.jpg": "/unhandled/path/test.jpg",
},
{
`C:\unhandled\path\assets\test.jpg`: `C:\unhandled\path\assets\test.jpg`,
},
}
for _, testCase := range testCases {
for input, expectedOutput := range testCase {
resourceCreate := &store.Resource{
CreatorID: user.ID,
InternalPath: input,
}
createdResource, err := ts.CreateResource(ctx, resourceCreate)
require.NoError(t, err)
err = ts.MigrateResourceInternalPath(ctx)
require.NoError(t, err)
findResource := &store.FindResource{
ID: &createdResource.ID,
}
resource, err := ts.GetResource(ctx, findResource)
require.NoError(t, err)
require.Equal(t, expectedOutput, resource.InternalPath)
}
}
ts.Close()
}
Loading…
Cancel
Save