github.com/friesencr/pop/v6@v6.1.6/file_migrator.go (about)

     1  package pop
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"github.com/friesencr/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.Store.Exec(content)
    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  
    76  			mf := Migration{
    77  				Path:          p,
    78  				Version:       match.Version,
    79  				Name:          match.Name,
    80  				DBType:        match.DBType,
    81  				Direction:     match.Direction,
    82  				Type:          match.Type,
    83  				NoTransaction: match.NoTransaction,
    84  				Runner:        runner,
    85  			}
    86  			switch mf.Direction {
    87  			case "up":
    88  				fm.UpMigrations.Migrations = append(fm.UpMigrations.Migrations, mf)
    89  			case "down":
    90  				fm.DownMigrations.Migrations = append(fm.DownMigrations.Migrations, mf)
    91  			default:
    92  				// the regex only matches `(up|down)` for direction, so a panic here is appropriate
    93  				panic("got unknown migration direction " + mf.Direction)
    94  			}
    95  		}
    96  		return nil
    97  	})
    98  }