github.com/eatigo/migrate@v3.0.2-0.20210729130915-7610befb1b6b+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  	"strings"
    13  
    14  	"github.com/eatigo/migrate/source"
    15  )
    16  
    17  func init() {
    18  	source.Register("file", &File{})
    19  }
    20  
    21  type File struct {
    22  	url        string
    23  	pathMap    map[string]string
    24  	path       string
    25  	migrations *source.Migrations
    26  }
    27  
    28  type fileInfoExt struct {
    29  	os.FileInfo
    30  	path string
    31  }
    32  
    33  func (f *File) listFiles(dirs string) ([]fileInfoExt, error) {
    34  	urls := strings.Split(dirs, ",")
    35  
    36  	var files []fileInfoExt
    37  	for _, url := range urls {
    38  		u, err := nurl.Parse(url)
    39  		if err != nil {
    40  			return nil, err
    41  		}
    42  
    43  		// concat host and path to restore full path
    44  		// host might be `.`
    45  		p := u.Host + u.Path
    46  
    47  		if len(p) == 0 {
    48  			// default to current directory if no path
    49  			wd, err := os.Getwd()
    50  			if err != nil {
    51  				return nil, err
    52  			}
    53  			p = wd
    54  
    55  		} else if p[0:1] == "." || p[0:1] != "/" {
    56  			// make path absolute if relative
    57  			abs, err := filepath.Abs(p)
    58  			if err != nil {
    59  				return nil, err
    60  			}
    61  			p = abs
    62  		}
    63  
    64  		// scan directory
    65  		localFiles, err := ioutil.ReadDir(p)
    66  		if err != nil {
    67  			return nil, err
    68  		}
    69  
    70  		for _, fi := range localFiles {
    71  			files = append(files, fileInfoExt{FileInfo: fi, path: p})
    72  		}
    73  	}
    74  
    75  	return files, nil
    76  }
    77  
    78  func (f *File) Open(url string) (source.Driver, error) {
    79  
    80  	files, err := f.listFiles(url)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	nf := &File{
    86  		url:        url,
    87  		migrations: source.NewMigrations(),
    88  		path:       url,
    89  		pathMap:    map[string]string{},
    90  	}
    91  
    92  	for _, fi := range files {
    93  		if !fi.IsDir() {
    94  			m, err := source.DefaultParse(fi.Name())
    95  			if err != nil {
    96  				continue // ignore files that we can't parse
    97  			}
    98  			if !nf.migrations.Append(m) {
    99  				return nil, fmt.Errorf("unable to parse file %v", fi.Name())
   100  			}
   101  			nf.pathMap[fi.Name()] = fi.path
   102  		}
   103  	}
   104  
   105  	return nf, nil
   106  }
   107  
   108  func (f *File) Close() error {
   109  	// nothing do to here
   110  	return nil
   111  }
   112  
   113  func (f *File) First() (version uint, err error) {
   114  	if v, ok := f.migrations.First(); !ok {
   115  		return 0, &os.PathError{"first", f.path, os.ErrNotExist}
   116  	} else {
   117  		return v, nil
   118  	}
   119  }
   120  
   121  func (f *File) Prev(version uint) (prevVersion uint, err error) {
   122  	if v, ok := f.migrations.Prev(version); !ok {
   123  		return 0, &os.PathError{fmt.Sprintf("prev for version %v", version), f.path, os.ErrNotExist}
   124  	} else {
   125  		return v, nil
   126  	}
   127  }
   128  
   129  func (f *File) Next(version uint) (nextVersion uint, err error) {
   130  	if v, ok := f.migrations.Next(version); !ok {
   131  		return 0, &os.PathError{fmt.Sprintf("next for version %v", version), f.path, os.ErrNotExist}
   132  	} else {
   133  		return v, nil
   134  	}
   135  }
   136  
   137  func (f *File) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) {
   138  	if m, ok := f.migrations.Up(version); ok {
   139  		r, err := os.Open(path.Join(f.pathMap[m.Raw], m.Raw))
   140  		if err != nil {
   141  			return nil, "", err
   142  		}
   143  		return r, m.Identifier, nil
   144  	}
   145  	return nil, "", &os.PathError{fmt.Sprintf("read version %v", version), f.path, os.ErrNotExist}
   146  }
   147  
   148  func (f *File) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) {
   149  	if m, ok := f.migrations.Down(version); ok {
   150  		r, err := os.Open(path.Join(f.pathMap[m.Raw], m.Raw))
   151  		if err != nil {
   152  			return nil, "", err
   153  		}
   154  		return r, m.Identifier, nil
   155  	}
   156  	return nil, "", &os.PathError{fmt.Sprintf("read version %v", version), f.path, os.ErrNotExist}
   157  }