github.com/bdollma-te/migrate/v4@v4.17.0-clickv2/source/pkger/pkger.go (about)

     1  package pkger
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	stdurl "net/url"
     7  
     8  	"github.com/bdollma-te/migrate/v4/source"
     9  	"github.com/bdollma-te/migrate/v4/source/httpfs"
    10  	"github.com/markbates/pkger"
    11  	"github.com/markbates/pkger/pkging"
    12  )
    13  
    14  func init() {
    15  	source.Register("pkger", &Pkger{})
    16  }
    17  
    18  // Pkger is a source.Driver that reads migrations from instances of
    19  // pkging.Pkger.
    20  type Pkger struct {
    21  	httpfs.PartialDriver
    22  }
    23  
    24  // Open implements source.Driver. The path component of url will be used as the
    25  // relative location of migrations. The returned driver will use the package
    26  // scoped pkger.Open to access migrations.  The relative root and any
    27  // migrations must be added to the global pkger.Pkger instance by calling
    28  // pkger.Apply. Refer to Pkger documentation for more information.
    29  func (p *Pkger) Open(url string) (source.Driver, error) {
    30  	u, err := stdurl.Parse(url)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	// wrap pkger to implement http.FileSystem.
    36  	fs := fsFunc(func(name string) (http.File, error) {
    37  		f, err := pkger.Open(name)
    38  		if err != nil {
    39  			return nil, err
    40  		}
    41  		return f.(http.File), nil
    42  	})
    43  
    44  	if err := p.Init(fs, u.Path); err != nil {
    45  		return nil, fmt.Errorf("failed to init driver with relative path %q: %w", u.Path, err)
    46  	}
    47  
    48  	return p, nil
    49  }
    50  
    51  // WithInstance returns a source.Driver that is backed by an instance of
    52  // pkging.Pkger. The relative location of migrations is indicated by path. The
    53  // path must exist on the pkging.Pkger instance for the driver to initialize
    54  // successfully.
    55  func WithInstance(instance pkging.Pkger, path string) (source.Driver, error) {
    56  	if instance == nil {
    57  		return nil, fmt.Errorf("expected instance of pkging.Pkger")
    58  	}
    59  
    60  	// wrap pkger to implement http.FileSystem.
    61  	fs := fsFunc(func(name string) (http.File, error) {
    62  		f, err := instance.Open(name)
    63  		if err != nil {
    64  			return nil, err
    65  		}
    66  		return f.(http.File), nil
    67  	})
    68  
    69  	var p Pkger
    70  
    71  	if err := p.Init(fs, path); err != nil {
    72  		return nil, fmt.Errorf("failed to init driver with relative path %q: %w", path, err)
    73  	}
    74  
    75  	return &p, nil
    76  }
    77  
    78  type fsFunc func(name string) (http.File, error)
    79  
    80  // Open implements http.FileSystem.
    81  func (f fsFunc) Open(name string) (http.File, error) {
    82  	return f(name)
    83  }