github.com/dkishere/pop/v6@v6.103.1/file_migrator.go (about)

     1  package pop
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"github.com/dkishere/pop/v6/logging"
    10  )
    11  
    12  // FileMigrator is a migrator for SQL and Fizz
    13  // files on disk at a specified path.
    14  type FileMigrator struct {
    15  	Migrator
    16  	Path string
    17  }
    18  
    19  // NewFileMigrator for a path and a Connection
    20  func NewFileMigrator(path string, c *Connection) (FileMigrator, error) {
    21  	fm := FileMigrator{
    22  		Migrator: NewMigrator(c),
    23  		Path:     path,
    24  	}
    25  	fm.SchemaPath = path
    26  
    27  	runner := func(mf Migration, tx *Connection) error {
    28  		f, err := os.Open(mf.Path)
    29  		if err != nil {
    30  			return err
    31  		}
    32  		defer f.Close()
    33  		content, err := MigrationContent(mf, tx, f, true)
    34  		if err != nil {
    35  			return fmt.Errorf("error processing %s: %w", mf.Path, err)
    36  		}
    37  		if content == "" {
    38  			return nil
    39  		}
    40  		err = tx.RawQuery(content).Exec()
    41  		if err != nil {
    42  			return fmt.Errorf("error executing %s, sql: %s: %w", mf.Path, content, err)
    43  		}
    44  		return nil
    45  	}
    46  
    47  	err := fm.findMigrations(runner)
    48  	if err != nil {
    49  		return fm, err
    50  	}
    51  
    52  	return fm, nil
    53  }
    54  
    55  func (fm *FileMigrator) findMigrations(runner func(mf Migration, tx *Connection) error) error {
    56  	dir := fm.Path
    57  	if fi, err := os.Stat(dir); err != nil || !fi.IsDir() {
    58  		// directory doesn't exist
    59  		return nil
    60  	}
    61  	return filepath.Walk(dir, func(p string, info os.FileInfo, err error) error {
    62  		if !info.IsDir() {
    63  			match, err := ParseMigrationFilename(info.Name())
    64  			if err != nil {
    65  				if strings.HasPrefix(err.Error(), "unsupported dialect") {
    66  					log(logging.Warn, "ignoring migration file with %s", err.Error())
    67  					return nil
    68  				}
    69  				return err
    70  			}
    71  			if match == nil {
    72  				log(logging.Warn, "ignoring file %s because it does not match the migration file pattern", info.Name())
    73  				return nil
    74  			}
    75  			mf := Migration{
    76  				Path:      p,
    77  				Version:   match.Version,
    78  				Name:      match.Name,
    79  				DBType:    match.DBType,
    80  				Direction: match.Direction,
    81  				Type:      match.Type,
    82  				Runner:    runner,
    83  			}
    84  			switch mf.Direction {
    85  			case "up":
    86  				fm.UpMigrations.Migrations = append(fm.UpMigrations.Migrations, mf)
    87  			case "down":
    88  				fm.DownMigrations.Migrations = append(fm.DownMigrations.Migrations, mf)
    89  			default:
    90  				// the regex only matches `(up|down)` for direction, so a panic here is appropriate
    91  				panic("got unknown migration direction " + mf.Direction)
    92  			}
    93  		}
    94  		return nil
    95  	})
    96  }