github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/lib/load.go (about)

     1  package lib
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/qri-io/dataset"
     9  	"github.com/qri-io/qri/base"
    10  	"github.com/qri-io/qri/base/dsfs"
    11  	"github.com/qri-io/qri/dsref"
    12  	qerr "github.com/qri-io/qri/errors"
    13  )
    14  
    15  type datasetLoader struct {
    16  	inst      *Instance
    17  	userOwner string
    18  	source    string
    19  }
    20  
    21  func newDatasetLoader(inst *Instance, userOwner, source string) dsref.Loader {
    22  	return &datasetLoader{
    23  		inst:      inst,
    24  		userOwner: userOwner,
    25  		source:    source,
    26  	}
    27  }
    28  
    29  // LoadDataset loads a dataset by resolving where it is available according to
    30  // the source being used, and loading it from there
    31  func (d *datasetLoader) LoadDataset(ctx context.Context, refstr string) (*dataset.Dataset, error) {
    32  	if d == nil {
    33  		return nil, fmt.Errorf("no datasetLoader")
    34  	}
    35  	if d.inst == nil {
    36  		return nil, fmt.Errorf("no instance")
    37  	}
    38  
    39  	ref, err := dsref.Parse(refstr)
    40  	if err != nil {
    41  		return nil, fmt.Errorf("%q is not a valid dataset reference: %w", refstr, err)
    42  	}
    43  
    44  	if ref.Username == "me" {
    45  		if d.userOwner == "" {
    46  			msg := fmt.Sprintf(`Can't use the "me" keyword to refer to a dataset in this context.
    47  Replace "me" with your username for the reference:
    48  %s`, refstr)
    49  			return nil, qerr.New(fmt.Errorf("invalid contextual reference"), msg)
    50  		}
    51  		ref.Username = d.userOwner
    52  	}
    53  
    54  	resolver, err := d.inst.resolverForSource(d.source)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	// Resolve the reference
    60  	location, err := resolver.ResolveRef(ctx, &ref)
    61  	if err != nil {
    62  		if errors.Is(err, dsref.ErrRefNotFound) {
    63  			return nil, qerr.New(err, fmt.Sprintf("reference %q not found", refstr))
    64  		}
    65  		return nil, err
    66  	}
    67  
    68  	if ref.Path == "" {
    69  		err = qerr.New(dsref.ErrNoHistory, fmt.Sprintf("can't load dataset %q, it has no saved versions", ref.Human()))
    70  		return nil, err
    71  	}
    72  
    73  	return d.loadRefFromLocation(ctx, ref, location)
    74  }
    75  
    76  // LoadDataset fetches, dereferences and opens a dataset from a reference
    77  // implements the dsfs.Loader interface
    78  // this function expects the passed in reference is fully resolved
    79  func (d *datasetLoader) loadRefFromLocation(ctx context.Context, ref dsref.Ref, location string) (*dataset.Dataset, error) {
    80  	if location == "" {
    81  		return d.loadLocalDataset(ctx, ref)
    82  	}
    83  
    84  	msg := fmt.Sprintf("pulling %s from %s ...\n", ref.Human(), location)
    85  	if d.inst.streams.Out != nil {
    86  		d.inst.streams.Out.Write([]byte(msg))
    87  	}
    88  
    89  	// TODO (b5) - it'd be nice to use the returned dataset here, skipping the
    90  	// loadLocalDataset call entirely. For that to work dsfs.LoadDataset &
    91  	// inst.loadLocalDataset would have to behave in exactly the same way, and
    92  	// currently they don't
    93  	if _, err := d.inst.remoteClient.PullDataset(ctx, &ref, location); err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	return d.loadLocalDataset(ctx, ref)
    98  }
    99  
   100  func (d *datasetLoader) loadLocalDataset(ctx context.Context, ref dsref.Ref) (*dataset.Dataset, error) {
   101  	// Load from dsfs
   102  	ds, err := dsfs.LoadDataset(ctx, d.inst.qfs, ref.Path)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	// Set transient info on the returned dataset
   107  	ds.Name = ref.Name
   108  	ds.Peername = ref.Username
   109  	ds.ID = ref.InitID
   110  
   111  	if err = base.OpenDataset(ctx, d.inst.repo.Filesystem(), ds); err != nil {
   112  		log.Debugf("Get dataset, base.OpenDataset failed, error: %s", err)
   113  		return nil, err
   114  	}
   115  
   116  	return ds, nil
   117  }