Unify user data directory from fragmented layout to consistent nested format: - Move WebDAV from: data/files/<username> → data/<username>/files/ - Move CalDAV from: data/<username>/cal-<name> → data/<username>/calendars/<name> - Move CardDAV from: data/<username>/card-<name> → data/<username>/addressbooks/<name> Changes: - internal/store/store.go: Update collectionPath() to map collection names - internal/store/migrate.go: Add idempotent Migrate() method - internal/store/migrate_test.go: Comprehensive migration tests - internal/webdav/handler.go: Use new unified path structure - cmd/server/main.go: Auto-run migration on startup - tools/nidusctl/main.go: Add migrate subcommand - Update tests to verify new structure URL endpoints unchanged - only on-disk structure modified. All tests pass.
64 lines
1.5 KiB
Go
64 lines
1.5 KiB
Go
// Command migrate is a tool to restructure the data directory from the
|
|
// old format to the new unified format.
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
|
|
"github.com/yourusername/caldav-server/internal/config"
|
|
"github.com/yourusername/caldav-server/internal/store"
|
|
)
|
|
|
|
func main() {
|
|
os.Exit(run(os.Args[1:]))
|
|
}
|
|
|
|
func run(args []string) int {
|
|
fs := flag.NewFlagSet("migrate", flag.ContinueOnError)
|
|
cfgPath := fs.String("config", "config.yaml", "path to configuration file")
|
|
verbose := fs.Bool("verbose", false, "enable verbose output")
|
|
if err := fs.Parse(args); err != nil {
|
|
return 2
|
|
}
|
|
|
|
cfg, err := config.Load(*cfgPath)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "error loading config: %v\n", err)
|
|
return 1
|
|
}
|
|
|
|
logger := buildLogger(*verbose)
|
|
|
|
st, err := store.NewStore(cfg.Storage.DataDir)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "error opening store %q: %v\n", cfg.Storage.DataDir, err)
|
|
return 1
|
|
}
|
|
|
|
logger.Info("starting migration", "data_dir", cfg.Storage.DataDir)
|
|
|
|
if err := st.Migrate(); err != nil {
|
|
logger.Error("migration failed", "error", err)
|
|
fmt.Fprintf(os.Stderr, "migration failed: %v\n", err)
|
|
return 1
|
|
}
|
|
|
|
logger.Info("migration completed successfully")
|
|
fmt.Println("Migration completed successfully")
|
|
return 0
|
|
}
|
|
|
|
func buildLogger(verbose bool) *slog.Logger {
|
|
level := slog.LevelInfo
|
|
if verbose {
|
|
level = slog.LevelDebug
|
|
}
|
|
handler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
|
|
Level: level,
|
|
})
|
|
return slog.New(handler)
|
|
}
|