github.com/status-im/migrate/v4@v4.6.2-status.3/source/file/file.go (about)

     1  package file
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	nurl "net/url"
     8  	"os"
     9  	"path"
    10  	"path/filepath"
    11  
    12  	"github.com/golang-migrate/migrate/v4/source"
    13  )
    14  
    15  func init() {
    16  	source.Register("file", &File{})
    17  }
    18  
    19  type File struct {
    20  	url        string
    21  	path       string
    22  	migrations *source.Migrations
    23  }
    24  
    25  func (f *File) Open(url string) (source.Driver, error) {
    26  	u, err := nurl.Parse(url)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  
    31  	// concat host and path to restore full path
    32  	// host might be `.`
    33  	p := u.Opaque
    34  	if len(p) == 0 {
    35  		p = u.Host + u.Path
    36  	}
    37  
    38  	if len(p) == 0 {
    39  		// default to current directory if no path
    40  		wd, err := os.Getwd()
    41  		if err != nil {
    42  			return nil, err
    43  		}
    44  		p = wd
    45  
    46  	} else if p[0:1] == "." || p[0:1] != "/" {
    47  		// make path absolute if relative
    48  		abs, err := filepath.Abs(p)
    49  		if err != nil {
    50  			return nil, err
    51  		}
    52  		p = abs
    53  	}
    54  
    55  	// scan directory
    56  	files, err := ioutil.ReadDir(p)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	nf := &File{
    62  		url:        url,
    63  		path:       p,
    64  		migrations: source.NewMigrations(),
    65  	}
    66  
    67  	for _, fi := range files {
    68  		if !fi.IsDir() {
    69  			m, err := source.DefaultParse(fi.Name())
    70  			if err != nil {
    71  				continue // ignore files that we can't parse
    72  			}
    73  			if !nf.migrations.Append(m) {
    74  				return nil, fmt.Errorf("unable to parse file %v", fi.Name())
    75  			}
    76  		}
    77  	}
    78  	return nf, nil
    79  }
    80  
    81  func (f *File) Close() error {
    82  	// nothing do to here
    83  	return nil
    84  }
    85  
    86  func (f *File) First() (version uint, err error) {
    87  	if v, ok := f.migrations.First(); ok {
    88  		return v, nil
    89  	}
    90  	return 0, &os.PathError{Op: "first", Path: f.path, Err: os.ErrNotExist}
    91  }
    92  
    93  func (f *File) Prev(version uint) (prevVersion uint, err error) {
    94  	if v, ok := f.migrations.Prev(version); ok {
    95  		return v, nil
    96  	}
    97  	return 0, &os.PathError{Op: fmt.Sprintf("prev for version %v", version), Path: f.path, Err: os.ErrNotExist}
    98  }
    99  
   100  func (f *File) Next(version uint) (nextVersion uint, err error) {
   101  	if v, ok := f.migrations.Next(version); ok {
   102  		return v, nil
   103  	}
   104  	return 0, &os.PathError{Op: fmt.Sprintf("next for version %v", version), Path: f.path, Err: os.ErrNotExist}
   105  }
   106  
   107  func (f *File) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) {
   108  	if m, ok := f.migrations.Up(version); ok {
   109  		r, err := os.Open(path.Join(f.path, m.Raw))
   110  		if err != nil {
   111  			return nil, "", err
   112  		}
   113  		return r, m.Identifier, nil
   114  	}
   115  	return nil, "", &os.PathError{Op: fmt.Sprintf("read version %v", version), Path: f.path, Err: os.ErrNotExist}
   116  }
   117  
   118  func (f *File) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) {
   119  	if m, ok := f.migrations.Down(version); ok {
   120  		r, err := os.Open(path.Join(f.path, m.Raw))
   121  		if err != nil {
   122  			return nil, "", err
   123  		}
   124  		return r, m.Identifier, nil
   125  	}
   126  	return nil, "", &os.PathError{Op: fmt.Sprintf("read version %v", version), Path: f.path, Err: os.ErrNotExist}
   127  }