MCPcopy Index your code
hub / github.com/riverqueue/river / migrationsFromFS

Function migrationsFromFS

rivermigrate/river_migrate.go:776–862  ·  view source on GitHub ↗

Reads a series of migration bundles from a file system, which practically speaking will always be the embedded FS read from the contents of the `migration/ /` subdirectory.

(migrationFS fs.FS, line string)

Source from the content-addressed store, hash-verified

774// speaking will always be the embedded FS read from the contents of the
775// `migration/<line>/` subdirectory.
776func migrationsFromFS(migrationFS fs.FS, line string) ([]Migration, error) {
777 const subdir = "migration"
778
779 var (
780 lastBundle *Migration
781 migrations []Migration
782 )
783
784 err := fs.WalkDir(migrationFS, subdir, func(path string, entry fs.DirEntry, err error) error {
785 if err != nil {
786 return fmt.Errorf("error walking FS: %w", err)
787 }
788
789 // The WalkDir callback is invoked for each embedded subdirectory and
790 // file. For our purposes here, we're only interested in files.
791 if entry.IsDir() {
792 return nil
793 }
794
795 filename := path
796
797 // Invoked with the full path name. Strip `migration/` from the front so
798 // we have a name that we can parse with.
799 if !strings.HasPrefix(filename, subdir) {
800 return fmt.Errorf("expected path %q to start with subdir %q", path, subdir)
801 }
802 filename = filename[len(subdir)+1:]
803
804 // Ignore any migrations that don't belong to the line we're reading.
805 if !strings.HasPrefix(filename, line) {
806 return nil
807 }
808 filename = filename[len(line)+1:]
809
810 versionStr, name, ok := strings.Cut(filename, "_")
811 if !ok {
812 return fmt.Errorf("expected name to start with version string like '001_': %q", filename)
813 }
814
815 version, err := strconv.Atoi(versionStr)
816 if err != nil {
817 return fmt.Errorf("error parsing version %q: %w", versionStr, err)
818 }
819
820 // Non-version name for the migration. So for `002_initial_schema` it
821 // would be `initial schema`.
822 name, _, _ = strings.Cut(name, ".")
823 name = strings.ReplaceAll(name, "_", " ")
824
825 // This works because `fs.WalkDir` guarantees lexical order, so all 001*
826 // files always appear before all 002* files, etc.
827 if lastBundle == nil || lastBundle.Version != version {
828 migrations = append(migrations, Migration{Name: name, Version: version})
829 lastBundle = &migrations[len(migrations)-1]
830 }
831
832 file, err := migrationFS.Open(path)
833 if err != nil {

Callers 3

NewFunction · 0.85
TestMigrationsFromFSFunction · 0.85

Calls 2

OpenMethod · 0.80
ErrorfMethod · 0.65

Tested by 2

TestMigrationsFromFSFunction · 0.68

Used in the wild real call sites across dependent graphs

searching dependent graphs…