github.com/nokia/migrate/v4@v4.16.0/migrate.go (about)

     1  // Package migrate reads migrations from sources and runs them against databases.
     2  // Sources are defined by the `source.Driver` and databases by the `database.Driver`
     3  // interface. The driver interfaces are kept "dumb", all migration logic is kept
     4  // in this package.
     5  package migrate
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  	"sync"
    13  	"time"
    14  
    15  	"github.com/hashicorp/go-multierror"
    16  
    17  	"github.com/nokia/migrate/v4/database"
    18  	iurl "github.com/nokia/migrate/v4/internal/url"
    19  	"github.com/nokia/migrate/v4/source"
    20  )
    21  
    22  // DefaultPrefetchMigrations sets the number of migrations to pre-read
    23  // from the source. This is helpful if the source is remote, but has little
    24  // effect for a local source (i.e. file system).
    25  // Please note that this setting has a major impact on the memory usage,
    26  // since each pre-read migration is buffered in memory. See DefaultBufferSize.
    27  var DefaultPrefetchMigrations = uint(10)
    28  
    29  // DefaultLockTimeout sets the max time a database driver has to acquire a lock.
    30  var DefaultLockTimeout = 15 * time.Second
    31  
    32  var (
    33  	ErrNoChange       = errors.New("no change")
    34  	ErrNilVersion     = errors.New("no migration")
    35  	ErrInvalidVersion = errors.New("version must be >= -1")
    36  	ErrLocked         = errors.New("database locked")
    37  	ErrLockTimeout    = errors.New("timeout: can't acquire database lock")
    38  )
    39  
    40  // ErrShortLimit is an error returned when not enough migrations
    41  // can be returned by a source for a given limit.
    42  type ErrShortLimit struct {
    43  	Short uint
    44  }
    45  
    46  // Error implements the error interface.
    47  func (e ErrShortLimit) Error() string {
    48  	return fmt.Sprintf("limit %v short", e.Short)
    49  }
    50  
    51  type ErrDirty struct {
    52  	Version int
    53  }
    54  
    55  func (e ErrDirty) Error() string {
    56  	return fmt.Sprintf("Dirty database version %v. Fix and force version.", e.Version)
    57  }
    58  
    59  type Migrate struct {
    60  	sourceName   string
    61  	sourceDrv    source.Driver
    62  	databaseName string
    63  	databaseDrv  database.Driver
    64  
    65  	// Log accepts a Logger interface
    66  	Log Logger
    67  
    68  	// GracefulStop accepts `true` and will stop executing migrations
    69  	// as soon as possible at a safe break point, so that the database
    70  	// is not corrupted.
    71  	GracefulStop chan bool
    72  	isLockedMu   *sync.Mutex
    73  
    74  	isGracefulStop bool
    75  	isLocked       bool
    76  
    77  	// PrefetchMigrations defaults to DefaultPrefetchMigrations,
    78  	// but can be set per Migrate instance.
    79  	PrefetchMigrations uint
    80  
    81  	// LockTimeout defaults to DefaultLockTimeout,
    82  	// but can be set per Migrate instance.
    83  	LockTimeout time.Duration
    84  
    85  	// Current application release
    86  	AppReleaseStr string
    87  }
    88  
    89  // New returns a new Migrate instance from a source URL and a database URL.
    90  // The URL scheme is defined by each driver.
    91  func New(sourceURL, databaseURL string) (*Migrate, error) {
    92  	m := newCommon()
    93  
    94  	sourceName, err := iurl.SchemeFromURL(sourceURL)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	m.sourceName = sourceName
    99  
   100  	databaseName, err := iurl.SchemeFromURL(databaseURL)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	m.databaseName = databaseName
   105  
   106  	sourceDrv, err := source.Open(sourceURL)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	m.sourceDrv = sourceDrv
   111  
   112  	databaseDrv, err := database.Open(databaseURL)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	m.databaseDrv = databaseDrv
   117  
   118  	return m, nil
   119  }
   120  
   121  // NewWithDatabaseInstance returns a new Migrate instance from a source URL
   122  // and an existing database instance. The source URL scheme is defined by each driver.
   123  // Use any string that can serve as an identifier during logging as databaseName.
   124  // You are responsible for closing the underlying database client if necessary.
   125  func NewWithDatabaseInstance(sourceURL string, databaseName string, databaseInstance database.Driver) (*Migrate, error) {
   126  	m := newCommon()
   127  
   128  	sourceName, err := iurl.SchemeFromURL(sourceURL)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	m.sourceName = sourceName
   133  
   134  	m.databaseName = databaseName
   135  
   136  	sourceDrv, err := source.Open(sourceURL)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	m.sourceDrv = sourceDrv
   141  
   142  	m.databaseDrv = databaseInstance
   143  
   144  	return m, nil
   145  }
   146  
   147  // NewWithSourceInstance returns a new Migrate instance from an existing source instance
   148  // and a database URL. The database URL scheme is defined by each driver.
   149  // Use any string that can serve as an identifier during logging as sourceName.
   150  // You are responsible for closing the underlying source client if necessary.
   151  func NewWithSourceInstance(sourceName string, sourceInstance source.Driver, databaseURL string) (*Migrate, error) {
   152  	m := newCommon()
   153  
   154  	databaseName, err := iurl.SchemeFromURL(databaseURL)
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  	m.databaseName = databaseName
   159  
   160  	m.sourceName = sourceName
   161  
   162  	databaseDrv, err := database.Open(databaseURL)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	m.databaseDrv = databaseDrv
   167  
   168  	m.sourceDrv = sourceInstance
   169  
   170  	return m, nil
   171  }
   172  
   173  // NewWithInstance returns a new Migrate instance from an existing source and
   174  // database instance. Use any string that can serve as an identifier during logging
   175  // as sourceName and databaseName. You are responsible for closing down
   176  // the underlying source and database client if necessary.
   177  func NewWithInstance(sourceName string, sourceInstance source.Driver, databaseName string, databaseInstance database.Driver) (*Migrate, error) {
   178  	m := newCommon()
   179  
   180  	m.sourceName = sourceName
   181  	m.databaseName = databaseName
   182  
   183  	m.sourceDrv = sourceInstance
   184  	m.databaseDrv = databaseInstance
   185  
   186  	return m, nil
   187  }
   188  
   189  func newCommon() *Migrate {
   190  	return &Migrate{
   191  		GracefulStop:       make(chan bool, 1),
   192  		PrefetchMigrations: DefaultPrefetchMigrations,
   193  		LockTimeout:        DefaultLockTimeout,
   194  		isLockedMu:         &sync.Mutex{},
   195  	}
   196  }
   197  
   198  // Close closes the source and the database.
   199  func (m *Migrate) Close() (source error, database error) {
   200  	databaseSrvClose := make(chan error)
   201  	sourceSrvClose := make(chan error)
   202  
   203  	m.logVerbosePrintf("Closing source and database\n")
   204  
   205  	go func() {
   206  		databaseSrvClose <- m.databaseDrv.Close()
   207  	}()
   208  
   209  	go func() {
   210  		sourceSrvClose <- m.sourceDrv.Close()
   211  	}()
   212  
   213  	return <-sourceSrvClose, <-databaseSrvClose
   214  }
   215  
   216  // Migrate looks at the currently active migration version,
   217  // then migrates either up or down to the specified version.
   218  func (m *Migrate) Migrate(version uint) error {
   219  	if err := m.lock(); err != nil {
   220  		return err
   221  	}
   222  
   223  	curVersion, dirty, err := m.databaseDrv.Version()
   224  	if err != nil {
   225  		return m.unlockErr(err)
   226  	}
   227  
   228  	if dirty {
   229  		return m.unlockErr(ErrDirty{curVersion})
   230  	}
   231  
   232  	ret := make(chan interface{}, m.PrefetchMigrations)
   233  	go m.read(curVersion, int(version), ret)
   234  
   235  	return m.unlockErr(m.runMigrations(ret))
   236  }
   237  
   238  // Steps looks at the currently active migration version.
   239  // It will migrate up if n > 0, and down if n < 0.
   240  func (m *Migrate) Steps(n int) error {
   241  	if n == 0 {
   242  		return ErrNoChange
   243  	}
   244  
   245  	if err := m.lock(); err != nil {
   246  		return err
   247  	}
   248  
   249  	curVersion, dirty, err := m.databaseDrv.Version()
   250  	if err != nil {
   251  		return m.unlockErr(err)
   252  	}
   253  
   254  	if dirty {
   255  		return m.unlockErr(ErrDirty{curVersion})
   256  	}
   257  
   258  	ret := make(chan interface{}, m.PrefetchMigrations)
   259  
   260  	if n > 0 {
   261  		go m.readUp(curVersion, n, ret)
   262  	} else {
   263  		go m.readDown(curVersion, -n, ret)
   264  	}
   265  
   266  	return m.unlockErr(m.runMigrations(ret))
   267  }
   268  
   269  // Up looks at the currently active migration version
   270  // and will migrate all the way up (applying all up migrations).
   271  func (m *Migrate) Up() error {
   272  	if err := m.lock(); err != nil {
   273  		return err
   274  	}
   275  
   276  	curVersion, dirty, err := m.databaseDrv.Version()
   277  	if err != nil {
   278  		return m.unlockErr(err)
   279  	}
   280  
   281  	if curVersion >= 0 {
   282  		if dirty {
   283  			m.sourceDrv.MarkSkipMigrations(uint(curVersion-1), source.Up)
   284  		} else {
   285  			m.sourceDrv.MarkSkipMigrations(uint(curVersion), source.Up)
   286  		}
   287  	}
   288  
   289  	if dirty {
   290  		return m.unlockErr(ErrDirty{curVersion})
   291  	}
   292  
   293  	ret := make(chan interface{}, m.PrefetchMigrations)
   294  	go m.readUp(curVersion, -1, ret)
   295  	m.sourceDrv.PrintSummary(source.Up)
   296  	err = m.runMigrations(ret)
   297  	m.sourceDrv.PrintSummary(source.Up)
   298  	return m.unlockErr(err)
   299  }
   300  
   301  // Down looks at the currently active migration version
   302  // and will migrate all the way down (applying all down migrations).
   303  func (m *Migrate) Down() error {
   304  	if err := m.lock(); err != nil {
   305  		return err
   306  	}
   307  
   308  	curVersion, dirty, err := m.databaseDrv.Version()
   309  	if err != nil {
   310  		return m.unlockErr(err)
   311  	}
   312  
   313  	if dirty {
   314  		return m.unlockErr(ErrDirty{curVersion})
   315  	}
   316  
   317  	ret := make(chan interface{}, m.PrefetchMigrations)
   318  	go m.readDown(curVersion, -1, ret)
   319  	m.sourceDrv.PrintSummary(source.Down)
   320  	err = m.runMigrations(ret)
   321  	m.sourceDrv.PrintSummary(source.Down)
   322  	return m.unlockErr(err)
   323  }
   324  
   325  // Drop deletes everything in the database.
   326  func (m *Migrate) Drop() error {
   327  	if err := m.lock(); err != nil {
   328  		return err
   329  	}
   330  	if err := m.databaseDrv.Drop(); err != nil {
   331  		return m.unlockErr(err)
   332  	}
   333  	return m.unlock()
   334  }
   335  
   336  // Run runs any migration provided by you against the database.
   337  // It does not check any currently active version in database.
   338  // Usually you don't need this function at all. Use Migrate,
   339  // Steps, Up or Down instead.
   340  func (m *Migrate) Run(migration ...*Migration) error {
   341  	if len(migration) == 0 {
   342  		return ErrNoChange
   343  	}
   344  
   345  	if err := m.lock(); err != nil {
   346  		return err
   347  	}
   348  
   349  	curVersion, dirty, err := m.databaseDrv.Version()
   350  	if err != nil {
   351  		return m.unlockErr(err)
   352  	}
   353  
   354  	if dirty {
   355  		return m.unlockErr(ErrDirty{curVersion})
   356  	}
   357  
   358  	ret := make(chan interface{}, m.PrefetchMigrations)
   359  
   360  	go func() {
   361  		defer close(ret)
   362  		for _, migr := range migration {
   363  			if m.PrefetchMigrations > 0 && migr.Body != nil {
   364  				m.logVerbosePrintf("Start buffering %v\n", migr.LogString())
   365  			} else {
   366  				m.logVerbosePrintf("Scheduled %v\n", migr.LogString())
   367  			}
   368  
   369  			ret <- migr
   370  			go func(migr *Migration) {
   371  				if err := migr.Buffer(); err != nil {
   372  					m.logErr(err)
   373  				}
   374  			}(migr)
   375  		}
   376  	}()
   377  
   378  	return m.unlockErr(m.runMigrations(ret))
   379  }
   380  
   381  // Force sets a migration version.
   382  // It does not check any currently active version in database.
   383  // It resets the dirty state to false.
   384  func (m *Migrate) Force(version int) error {
   385  	if version < -1 {
   386  		return ErrInvalidVersion
   387  	}
   388  
   389  	if err := m.lock(); err != nil {
   390  		return err
   391  	}
   392  
   393  	if err := m.databaseDrv.SetVersion(version, false); err != nil {
   394  		return m.unlockErr(err)
   395  	}
   396  
   397  	return m.unlock()
   398  }
   399  
   400  // Version returns the currently active migration version.
   401  // If no migration has been applied, yet, it will return ErrNilVersion.
   402  func (m *Migrate) Version() (version uint, dirty bool, err error) {
   403  	v, d, err := m.databaseDrv.Version()
   404  	if err != nil {
   405  		return 0, false, err
   406  	}
   407  
   408  	if v == database.NilVersion {
   409  		return 0, false, ErrNilVersion
   410  	}
   411  
   412  	return suint(v), d, nil
   413  }
   414  
   415  // read reads either up or down migrations from source `from` to `to`.
   416  // Each migration is then written to the ret channel.
   417  // If an error occurs during reading, that error is written to the ret channel, too.
   418  // Once read is done reading it will close the ret channel.
   419  func (m *Migrate) read(from int, to int, ret chan<- interface{}) {
   420  	defer close(ret)
   421  
   422  	// check if from version exists
   423  	if from >= 0 {
   424  		if err := m.versionExists(suint(from)); err != nil {
   425  			ret <- err
   426  			return
   427  		}
   428  	}
   429  
   430  	// check if to version exists
   431  	if to >= 0 {
   432  		if err := m.versionExists(suint(to)); err != nil {
   433  			ret <- err
   434  			return
   435  		}
   436  	}
   437  
   438  	// no change?
   439  	if from == to {
   440  		ret <- ErrNoChange
   441  		return
   442  	}
   443  
   444  	if from < to {
   445  		// it's going up
   446  		// apply first migration if from is nil version
   447  		if from == -1 {
   448  			firstVersion, err := m.sourceDrv.First()
   449  			if err != nil {
   450  				ret <- err
   451  				return
   452  			}
   453  
   454  			migr, err := m.newMigration(firstVersion, int(firstVersion))
   455  			if err != nil {
   456  				ret <- err
   457  				return
   458  			}
   459  
   460  			ret <- migr
   461  			go func() {
   462  				if err := migr.Buffer(); err != nil {
   463  					m.logErr(err)
   464  				}
   465  			}()
   466  
   467  			from = int(firstVersion)
   468  		}
   469  
   470  		// run until we reach target ...
   471  		for from < to {
   472  			if m.stop() {
   473  				return
   474  			}
   475  
   476  			next, err := m.sourceDrv.Next(suint(from))
   477  			if err != nil {
   478  				ret <- err
   479  				return
   480  			}
   481  
   482  			migr, err := m.newMigration(next, int(next))
   483  			if err != nil {
   484  				ret <- err
   485  				return
   486  			}
   487  
   488  			ret <- migr
   489  			go func() {
   490  				if err := migr.Buffer(); err != nil {
   491  					m.logErr(err)
   492  				}
   493  			}()
   494  
   495  			from = int(next)
   496  		}
   497  
   498  	} else {
   499  		// it's going down
   500  		// run until we reach target ...
   501  		for from > to && from >= 0 {
   502  			if m.stop() {
   503  				return
   504  			}
   505  
   506  			prev, err := m.sourceDrv.Prev(suint(from))
   507  			if errors.Is(err, os.ErrNotExist) && to == -1 {
   508  				// apply nil migration
   509  				migr, err := m.newMigration(suint(from), -1)
   510  				if err != nil {
   511  					ret <- err
   512  					return
   513  				}
   514  				ret <- migr
   515  				go func() {
   516  					if err := migr.Buffer(); err != nil {
   517  						m.logErr(err)
   518  					}
   519  				}()
   520  
   521  				return
   522  
   523  			} else if err != nil {
   524  				ret <- err
   525  				return
   526  			}
   527  
   528  			migr, err := m.newMigration(suint(from), int(prev))
   529  			if err != nil {
   530  				ret <- err
   531  				return
   532  			}
   533  
   534  			ret <- migr
   535  			go func() {
   536  				if err := migr.Buffer(); err != nil {
   537  					m.logErr(err)
   538  				}
   539  			}()
   540  
   541  			from = int(prev)
   542  		}
   543  	}
   544  }
   545  
   546  // readUp reads up migrations from `from` limitted by `limit`.
   547  // limit can be -1, implying no limit and reading until there are no more migrations.
   548  // Each migration is then written to the ret channel.
   549  // If an error occurs during reading, that error is written to the ret channel, too.
   550  // Once readUp is done reading it will close the ret channel.
   551  func (m *Migrate) readUp(from int, limit int, ret chan<- interface{}) {
   552  	defer close(ret)
   553  
   554  	// check if from version exists
   555  	if from >= 0 {
   556  		if err := m.versionExists(suint(from)); err != nil {
   557  			ret <- err
   558  			return
   559  		}
   560  	}
   561  
   562  	if limit == 0 {
   563  		ret <- ErrNoChange
   564  		return
   565  	}
   566  
   567  	count := 0
   568  	for count < limit || limit == -1 {
   569  		if m.stop() {
   570  			return
   571  		}
   572  
   573  		// apply first migration if from is nil version
   574  		if from == -1 {
   575  			firstVersion, err := m.sourceDrv.First()
   576  			if err != nil {
   577  				ret <- err
   578  				return
   579  			}
   580  
   581  			migr, err := m.newMigration(firstVersion, int(firstVersion))
   582  			if err != nil {
   583  				ret <- err
   584  				return
   585  			}
   586  
   587  			ret <- migr
   588  			go func() {
   589  				if err := migr.Buffer(); err != nil {
   590  					m.logErr(err)
   591  				}
   592  			}()
   593  			from = int(firstVersion)
   594  			count++
   595  			continue
   596  		}
   597  
   598  		// apply next migration
   599  		next, err := m.sourceDrv.Next(suint(from))
   600  		if errors.Is(err, os.ErrNotExist) {
   601  			// no limit, but no migrations applied?
   602  			if limit == -1 && count == 0 {
   603  				ret <- ErrNoChange
   604  				return
   605  			}
   606  
   607  			// no limit, reached end
   608  			if limit == -1 {
   609  				return
   610  			}
   611  
   612  			// reached end, and didn't apply any migrations
   613  			if limit > 0 && count == 0 {
   614  				ret <- os.ErrNotExist
   615  				return
   616  			}
   617  
   618  			// applied less migrations than limit?
   619  			if count < limit {
   620  				ret <- ErrShortLimit{suint(limit - count)}
   621  				return
   622  			}
   623  		}
   624  		if err != nil {
   625  			ret <- err
   626  			return
   627  		}
   628  
   629  		migr, err := m.newMigration(next, int(next))
   630  		if err != nil {
   631  			ret <- err
   632  			return
   633  		}
   634  
   635  		ret <- migr
   636  		go func() {
   637  			if err := migr.Buffer(); err != nil {
   638  				m.logErr(err)
   639  			}
   640  		}()
   641  		from = int(next)
   642  		count++
   643  	}
   644  }
   645  
   646  // readDown reads down migrations from `from` limitted by `limit`.
   647  // limit can be -1, implying no limit and reading until there are no more migrations.
   648  // Each migration is then written to the ret channel.
   649  // If an error occurs during reading, that error is written to the ret channel, too.
   650  // Once readDown is done reading it will close the ret channel.
   651  func (m *Migrate) readDown(from int, limit int, ret chan<- interface{}) {
   652  	defer close(ret)
   653  
   654  	// check if from version exists
   655  	if from >= 0 {
   656  		if err := m.versionExists(suint(from)); err != nil {
   657  			ret <- err
   658  			return
   659  		}
   660  	}
   661  
   662  	if limit == 0 {
   663  		ret <- ErrNoChange
   664  		return
   665  	}
   666  
   667  	// no change if already at nil version
   668  	if from == -1 && limit == -1 {
   669  		ret <- ErrNoChange
   670  		return
   671  	}
   672  
   673  	// can't go over limit if already at nil version
   674  	if from == -1 && limit > 0 {
   675  		ret <- os.ErrNotExist
   676  		return
   677  	}
   678  
   679  	count := 0
   680  	for count < limit || limit == -1 {
   681  		if m.stop() {
   682  			return
   683  		}
   684  
   685  		prev, err := m.sourceDrv.Prev(suint(from))
   686  		if errors.Is(err, os.ErrNotExist) {
   687  			// no limit or haven't reached limit, apply "first" migration
   688  			if limit == -1 || limit-count > 0 {
   689  				firstVersion, err := m.sourceDrv.First()
   690  				if err != nil {
   691  					ret <- err
   692  					return
   693  				}
   694  
   695  				migr, err := m.newMigration(firstVersion, -1)
   696  				if err != nil {
   697  					ret <- err
   698  					return
   699  				}
   700  				ret <- migr
   701  				go func() {
   702  					if err := migr.Buffer(); err != nil {
   703  						m.logErr(err)
   704  					}
   705  				}()
   706  				count++
   707  			}
   708  
   709  			if count < limit {
   710  				ret <- ErrShortLimit{suint(limit - count)}
   711  			}
   712  			return
   713  		}
   714  		if err != nil {
   715  			ret <- err
   716  			return
   717  		}
   718  
   719  		migr, err := m.newMigration(suint(from), int(prev))
   720  		if err != nil {
   721  			ret <- err
   722  			return
   723  		}
   724  
   725  		ret <- migr
   726  		go func() {
   727  			if err := migr.Buffer(); err != nil {
   728  				m.logErr(err)
   729  			}
   730  		}()
   731  		from = int(prev)
   732  		count++
   733  	}
   734  }
   735  
   736  // runMigrations reads *Migration and error from a channel. Any other type
   737  // sent on this channel will result in a panic. Each migration is then
   738  // proxied to the database driver and run against the database.
   739  // Before running a newly received migration it will check if it's supposed
   740  // to stop execution because it might have received a stop signal on the
   741  // GracefulStop channel.
   742  func (m *Migrate) runMigrations(ret <-chan interface{}) error {
   743  	for r := range ret {
   744  
   745  		if m.stop() {
   746  			return nil
   747  		}
   748  
   749  		switch r := r.(type) {
   750  		case error:
   751  			return r
   752  
   753  		case *Migration:
   754  			migr := r
   755  
   756  			// set version with dirty state
   757  			if err := m.databaseDrv.SetVersion(migr.TargetVersion, true); err != nil {
   758  				return err
   759  			}
   760  
   761  			if migr.Body != nil {
   762  				m.logVerbosePrintf("Read and execute %v\n", migr.LogString())
   763  				if err := m.databaseDrv.Run(migr.BufferedBody); err != nil {
   764  					m.sourceDrv.UpdateStatus(migr.Version, source.Failed, err.Error())
   765  					return err
   766  				}
   767  			} else if migr.MigrationFunc != nil {
   768  				m.logVerbosePrintf("Running Migration function %v\n", migr.LogString())
   769  				if err := m.databaseDrv.RunFunctionMigration(migr.MigrationFunc); err != nil {
   770  					m.sourceDrv.UpdateStatus(migr.Version, source.Failed, err.Error())
   771  					return err
   772  				}
   773  			}
   774  
   775  			// set clean state
   776  			if err := m.databaseDrv.SetVersion(migr.TargetVersion, false); err != nil {
   777  				return err
   778  			}
   779  
   780  			endTime := time.Now()
   781  			readTime := migr.FinishedReading.Sub(migr.StartedBuffering)
   782  			runTime := endTime.Sub(migr.FinishedReading)
   783  
   784  			// update status
   785  			if migr.Skipped {
   786  				m.sourceDrv.UpdateStatus(migr.Version, source.Skipped, "")
   787  			} else {
   788  				m.sourceDrv.UpdateStatus(migr.Version, source.Done, "")
   789  			}
   790  			// log either verbose or normal
   791  			if m.Log != nil {
   792  				if m.Log.Verbose() {
   793  					m.logPrintf("Finished %v (read %v, ran %v)\n", migr.LogString(), readTime, runTime)
   794  				} else {
   795  					m.logPrintf("%v (%v)\n", migr.LogString(), readTime+runTime)
   796  				}
   797  			}
   798  
   799  		default:
   800  			return fmt.Errorf("unknown type: %T with value: %+v", r, r)
   801  		}
   802  	}
   803  	return nil
   804  }
   805  
   806  // versionExists checks the source if either the up or down migration for
   807  // the specified migration version exists.
   808  func (m *Migrate) versionExists(version uint) (result error) {
   809  	// try up migration first
   810  	up, _, _, _, err := m.sourceDrv.ReadUp(version)
   811  	if err == nil {
   812  		defer func() {
   813  			if up != nil {
   814  				if errClose := up.Close(); errClose != nil {
   815  					result = multierror.Append(result, errClose)
   816  				}
   817  			}
   818  		}()
   819  	}
   820  	if errors.Is(err, os.ErrExist) {
   821  		return nil
   822  	} else if !errors.Is(err, os.ErrNotExist) {
   823  		return err
   824  	}
   825  
   826  	// then try down migration
   827  	down, _, _, _, err := m.sourceDrv.ReadDown(version)
   828  	if err == nil {
   829  		defer func() {
   830  			if down != nil {
   831  				if errClose := down.Close(); errClose != nil {
   832  					result = multierror.Append(result, errClose)
   833  				}
   834  			}
   835  		}()
   836  	}
   837  	if errors.Is(err, os.ErrExist) {
   838  		return nil
   839  	} else if !errors.Is(err, os.ErrNotExist) {
   840  		return err
   841  	}
   842  
   843  	err = fmt.Errorf("no migration found for version %d: %w", version, err)
   844  	m.logErr(err)
   845  	return err
   846  }
   847  
   848  // stop returns true if no more migrations should be run against the database
   849  // because a stop signal was received on the GracefulStop channel.
   850  // Calls are cheap and this function is not blocking.
   851  func (m *Migrate) stop() bool {
   852  	if m.isGracefulStop {
   853  		return true
   854  	}
   855  
   856  	select {
   857  	case <-m.GracefulStop:
   858  		m.isGracefulStop = true
   859  		return true
   860  
   861  	default:
   862  		return false
   863  	}
   864  }
   865  
   866  // newMigration is a helper func that returns a *Migration for the
   867  // specified version and targetVersion.
   868  func (m *Migrate) newMigration(version uint, targetVersion int) (*Migration, error) {
   869  	var migr *Migration
   870  
   871  	if targetVersion >= int(version) {
   872  		r, identifier, loc, fn, err := m.sourceDrv.ReadUp(version)
   873  		// skip up migration based on current release
   874  		skipMgr := m.skipMigration(loc)
   875  		if errors.Is(err, os.ErrNotExist) {
   876  			// create "empty" migration
   877  			migr, err = NewMigration(nil, "", version, targetVersion)
   878  			if err != nil {
   879  				return nil, err
   880  			}
   881  
   882  		} else if skipMgr {
   883  			fmt.Printf("Skiping migration for :%v\n", loc)
   884  			migr = NewSkippedMigration("", version, targetVersion)
   885  		} else if err != nil {
   886  			return nil, err
   887  		} else if fn != nil {
   888  			// create migration with function
   889  			migr = NewFuncMigration(fn, identifier, version, targetVersion)
   890  		} else {
   891  			// create migration from up source
   892  			migr, err = NewMigration(r, identifier, version, targetVersion)
   893  			if err != nil {
   894  				return nil, err
   895  			}
   896  		}
   897  
   898  	} else {
   899  		r, identifier, _, fn, err := m.sourceDrv.ReadDown(version)
   900  		// lets not skip down migration based on release string.
   901  		if errors.Is(err, os.ErrNotExist) {
   902  			// create "empty" migration
   903  			migr, err = NewMigration(nil, "", version, targetVersion)
   904  			if err != nil {
   905  				return nil, err
   906  			}
   907  
   908  		} else if err != nil {
   909  			return nil, err
   910  		} else if fn != nil {
   911  			// create migration with function
   912  			migr = NewFuncMigration(fn, identifier, version, targetVersion)
   913  		} else {
   914  			// create migration from down source
   915  			migr, err = NewMigration(r, identifier, version, targetVersion)
   916  			if err != nil {
   917  				return nil, err
   918  			}
   919  		}
   920  	}
   921  
   922  	if m.PrefetchMigrations > 0 && migr.Body != nil {
   923  		m.logVerbosePrintf("Start buffering %v\n", migr.LogString())
   924  	} else {
   925  		m.logVerbosePrintf("Scheduled %v\n", migr.LogString())
   926  	}
   927  
   928  	return migr, nil
   929  }
   930  
   931  func (m *Migrate) skipMigration(location string) bool {
   932  	parentDir := filepath.Dir(location)
   933  	if parentDir != "." && parentDir < m.AppReleaseStr {
   934  		return true
   935  	}
   936  	return false
   937  }
   938  
   939  // lock is a thread safe helper function to lock the database.
   940  // It should be called as late as possible when running migrations.
   941  func (m *Migrate) lock() error {
   942  	m.isLockedMu.Lock()
   943  	defer m.isLockedMu.Unlock()
   944  
   945  	if m.isLocked {
   946  		return ErrLocked
   947  	}
   948  
   949  	// create done channel, used in the timeout goroutine
   950  	done := make(chan bool, 1)
   951  	defer func() {
   952  		done <- true
   953  	}()
   954  
   955  	// use errchan to signal error back to this context
   956  	errchan := make(chan error, 2)
   957  
   958  	// start timeout goroutine
   959  	timeout := time.After(m.LockTimeout)
   960  	go func() {
   961  		for {
   962  			select {
   963  			case <-done:
   964  				return
   965  			case <-timeout:
   966  				errchan <- ErrLockTimeout
   967  				return
   968  			}
   969  		}
   970  	}()
   971  
   972  	// now try to acquire the lock
   973  	go func() {
   974  		if err := m.databaseDrv.Lock(); err != nil {
   975  			errchan <- err
   976  		} else {
   977  			errchan <- nil
   978  		}
   979  	}()
   980  
   981  	// wait until we either receive ErrLockTimeout or error from Lock operation
   982  	err := <-errchan
   983  	if err == nil {
   984  		m.isLocked = true
   985  	}
   986  	return err
   987  }
   988  
   989  // unlock is a thread safe helper function to unlock the database.
   990  // It should be called as early as possible when no more migrations are
   991  // expected to be executed.
   992  func (m *Migrate) unlock() error {
   993  	m.isLockedMu.Lock()
   994  	defer m.isLockedMu.Unlock()
   995  
   996  	if err := m.databaseDrv.Unlock(); err != nil {
   997  		// BUG: Can potentially create a deadlock. Add a timeout.
   998  		return err
   999  	}
  1000  
  1001  	m.isLocked = false
  1002  	return nil
  1003  }
  1004  
  1005  // unlockErr calls unlock and returns a combined error
  1006  // if a prevErr is not nil.
  1007  func (m *Migrate) unlockErr(prevErr error) error {
  1008  	if err := m.unlock(); err != nil {
  1009  		return multierror.Append(prevErr, err)
  1010  	}
  1011  	return prevErr
  1012  }
  1013  
  1014  // logPrintf writes to m.Log if not nil
  1015  func (m *Migrate) logPrintf(format string, v ...interface{}) {
  1016  	if m.Log != nil {
  1017  		m.Log.Printf(format, v...)
  1018  	}
  1019  }
  1020  
  1021  // logVerbosePrintf writes to m.Log if not nil. Use for verbose logging output.
  1022  func (m *Migrate) logVerbosePrintf(format string, v ...interface{}) {
  1023  	if m.Log != nil && m.Log.Verbose() {
  1024  		m.Log.Printf(format, v...)
  1025  	}
  1026  }
  1027  
  1028  // logErr writes error to m.Log if not nil
  1029  func (m *Migrate) logErr(err error) {
  1030  	if m.Log != nil {
  1031  		m.Log.Printf("error: %v", err)
  1032  	}
  1033  }
  1034  
  1035  func (m *Migrate) GetDBDriver() database.Driver {
  1036  	return m.databaseDrv
  1037  }