github.com/dhui/migrate@v3.4.0+incompatible/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/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.Host + u.Path
    34  
    35  	if len(p) == 0 {
    36  		// default to current directory if no path
    37  		wd, err := os.Getwd()
    38  		if err != nil {
    39  			return nil, err
    40  		}
    41  		p = wd
    42  
    43  	} else if p[0:1] == "." || p[0:1] != "/" {
    44  		// make path absolute if relative
    45  		abs, err := filepath.Abs(p)
    46  		if err != nil {
    47  			return nil, err
    48  		}
    49  		p = abs
    50  	}
    51  
    52  	// scan directory
    53  	files, err := ioutil.ReadDir(p)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	nf := &File{
    59  		url:        url,
    60  		path:       p,
    61  		migrations: source.NewMigrations(),
    62  	}
    63  
    64  	for _, fi := range files {
    65  		if !fi.IsDir() {
    66  			m, err := source.DefaultParse(fi.Name())
    67  			if err != nil {
    68  				continue // ignore files that we can't parse
    69  			}
    70  			if !nf.migrations.Append(m) {
    71  				return nil, fmt.Errorf("unable to parse file %v", fi.Name())
    72  			}
    73  		}
    74  	}
    75  	return nf, nil
    76  }
    77  
    78  func (f *File) Close() error {
    79  	// nothing do to here
    80  	return nil
    81  }
    82  
    83  func (f *File) First() (version uint, err error) {
    84  	if v, ok := f.migrations.First(); !ok {
    85  		return 0, &os.PathError{Op: "first", Path: f.path, Err: os.ErrNotExist}
    86  	} else {
    87  		return v, nil
    88  	}
    89  }
    90  
    91  func (f *File) Prev(version uint) (prevVersion uint, err error) {
    92  	if v, ok := f.migrations.Prev(version); !ok {
    93  		return 0, &os.PathError{Op: fmt.Sprintf("prev for version %v", version), Path: f.path, Err: os.ErrNotExist}
    94  	} else {
    95  		return v, nil
    96  	}
    97  }
    98  
    99  func (f *File) Next(version uint) (nextVersion uint, err error) {
   100  	if v, ok := f.migrations.Next(version); !ok {
   101  		return 0, &os.PathError{Op: fmt.Sprintf("next for version %v", version), Path: f.path, Err: os.ErrNotExist}
   102  	} else {
   103  		return v, nil
   104  	}
   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  }