github.com/ghosta3/migrate@v3.5.4+incompatible/source/godoc_vfs/vfs.go (about)

     1  // Package vfs contains a driver that reads migrations from a virtual file
     2  // system.
     3  //
     4  // Implementations of the filesystem interface that read from zip files and
     5  // maps, as well as the definition of the filesystem interface can be found in
     6  // the golang.org/x/tools/godoc/vfs package.
     7  package godoc_vfs
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"io"
    13  	"io/ioutil"
    14  	"os"
    15  	"path"
    16  
    17  	"github.com/golang-migrate/migrate/source"
    18  	"golang.org/x/tools/godoc/vfs"
    19  )
    20  
    21  func init() {
    22  	source.Register("godoc-vfs", &VFS{})
    23  }
    24  
    25  // VFS is an implementation of driver that returns migrations from a virtual
    26  // file system.
    27  type VFS struct {
    28  	migrations *source.Migrations
    29  	fs         vfs.FileSystem
    30  	path       string
    31  }
    32  
    33  // Open implements the source.Driver interface for VFS.
    34  //
    35  // Calling this function panics, instead use the WithInstance function.
    36  // See the package level documentation for an example.
    37  func (b *VFS) Open(url string) (source.Driver, error) {
    38  	panic("not implemented")
    39  }
    40  
    41  // WithInstance creates a new driver from a virtual file system.
    42  // If a tree named searchPath exists in the virtual filesystem, WithInstance
    43  // searches for migration files there.
    44  // It defaults to "/".
    45  func WithInstance(fs vfs.FileSystem, searchPath string) (source.Driver, error) {
    46  	if searchPath == "" {
    47  		searchPath = "/"
    48  	}
    49  
    50  	bn := &VFS{
    51  		fs:         fs,
    52  		path:       searchPath,
    53  		migrations: source.NewMigrations(),
    54  	}
    55  
    56  	files, err := fs.ReadDir(searchPath)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	for _, fi := range files {
    62  		m, err := source.DefaultParse(fi.Name())
    63  		if err != nil {
    64  			continue // ignore files that we can't parse
    65  		}
    66  
    67  		if !bn.migrations.Append(m) {
    68  			return nil, fmt.Errorf("unable to parse file %v", fi)
    69  		}
    70  	}
    71  
    72  	return bn, nil
    73  }
    74  
    75  // Close implements the source.Driver interface for VFS.
    76  // It is a no-op and should not be used.
    77  func (b *VFS) Close() error {
    78  	return nil
    79  }
    80  
    81  // First returns the first migration verion found in the file system.
    82  // If no version is available os.ErrNotExist is returned.
    83  func (b *VFS) First() (version uint, err error) {
    84  	v, ok := b.migrations.First()
    85  	if !ok {
    86  		return 0, &os.PathError{"first", "<vfs>://" + b.path, os.ErrNotExist}
    87  	}
    88  	return v, nil
    89  }
    90  
    91  // Prev returns the previous version available to the driver.
    92  // If no previous version is available os.ErrNotExist is returned.
    93  func (b *VFS) Prev(version uint) (prevVersion uint, err error) {
    94  	v, ok := b.migrations.Prev(version)
    95  	if !ok {
    96  		return 0, &os.PathError{fmt.Sprintf("prev for version %v", version), "<vfs>://" + b.path, os.ErrNotExist}
    97  	}
    98  	return v, nil
    99  }
   100  
   101  // Prev returns the next version available to the driver.
   102  // If no previous version is available os.ErrNotExist is returned.
   103  func (b *VFS) Next(version uint) (nextVersion uint, err error) {
   104  	v, ok := b.migrations.Next(version)
   105  	if !ok {
   106  		return 0, &os.PathError{fmt.Sprintf("next for version %v", version), "<vfs>://" + b.path, os.ErrNotExist}
   107  	}
   108  	return v, nil
   109  }
   110  
   111  // ReadUp returns the up migration body and an identifier that helps with
   112  // finding this migration in the source.
   113  // If there is no up migration available for this version it returns
   114  // os.ErrNotExist.
   115  func (b *VFS) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) {
   116  	if m, ok := b.migrations.Up(version); ok {
   117  		body, err := vfs.ReadFile(b.fs, path.Join(b.path, m.Raw))
   118  		if err != nil {
   119  			return nil, "", err
   120  		}
   121  		return ioutil.NopCloser(bytes.NewReader(body)), m.Identifier, nil
   122  	}
   123  	return nil, "", &os.PathError{fmt.Sprintf("read version %v", version), "<vfs>://" + b.path, os.ErrNotExist}
   124  }
   125  
   126  // ReadDown returns the down migration body and an identifier that helps with
   127  // finding this migration  in the source.
   128  func (b *VFS) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) {
   129  	if m, ok := b.migrations.Down(version); ok {
   130  		body, err := vfs.ReadFile(b.fs, path.Join(b.path, m.Raw))
   131  		if err != nil {
   132  			return nil, "", err
   133  		}
   134  		return ioutil.NopCloser(bytes.NewReader(body)), m.Identifier, nil
   135  	}
   136  	return nil, "", &os.PathError{fmt.Sprintf("read version %v", version), "<vfs>://" + b.path, os.ErrNotExist}
   137  }