github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/repo/buildrepo/build.go (about)

     1  // Package buildrepo initializes a qri repo
     2  package buildrepo
     3  
     4  import (
     5  	"context"
     6  	"fmt"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	golog "github.com/ipfs/go-log"
    11  	"github.com/qri-io/qfs"
    12  	"github.com/qri-io/qfs/muxfs"
    13  	"github.com/qri-io/qri/auth/key"
    14  	"github.com/qri-io/qri/config"
    15  	"github.com/qri-io/qri/dscache"
    16  	"github.com/qri-io/qri/event"
    17  	"github.com/qri-io/qri/logbook"
    18  	"github.com/qri-io/qri/profile"
    19  	"github.com/qri-io/qri/repo"
    20  	fsrepo "github.com/qri-io/qri/repo/fs"
    21  )
    22  
    23  var log = golog.Logger("buildrepo")
    24  
    25  // Options provides additional fields to new
    26  type Options struct {
    27  	Profiles   profile.Store
    28  	Keystore   key.Store
    29  	Filesystem *muxfs.Mux
    30  	Logbook    *logbook.Book
    31  	Dscache    *dscache.Dscache
    32  	Bus        event.Bus
    33  }
    34  
    35  // New is the canonical method for building a repo
    36  func New(ctx context.Context, path string, cfg *config.Config, opts ...func(o *Options)) (repo.Repo, error) {
    37  	o := &Options{}
    38  	for _, opt := range opts {
    39  		opt(o)
    40  	}
    41  
    42  	// Don't create a localstore with the empty path, this will use the current directory
    43  	if cfg.Repo.Type == "fs" && cfg.Path() == "" {
    44  		return nil, fmt.Errorf("buildRepo.New using filesystem requires non-empty path")
    45  	}
    46  
    47  	var err error
    48  	if o.Keystore == nil {
    49  		log.Debug("buildrepo.New: creating keystore")
    50  		if o.Keystore, err = key.NewStore(cfg); err != nil {
    51  			return nil, err
    52  		}
    53  	}
    54  	if o.Profiles == nil {
    55  		log.Debug("buildrepo.New: creating profiles")
    56  		if o.Profiles, err = profile.NewStore(ctx, cfg, o.Keystore); err != nil {
    57  			return nil, err
    58  		}
    59  	}
    60  	if o.Filesystem == nil {
    61  		log.Debug("buildrepo.New: creating filesystem")
    62  		if o.Filesystem, err = NewFilesystem(ctx, cfg); err != nil {
    63  			return nil, err
    64  		}
    65  	}
    66  	if o.Bus == nil {
    67  		log.Debug("buildrepo.New: creating bus")
    68  		o.Bus = event.NilBus
    69  	}
    70  
    71  	pro := o.Profiles.Owner(ctx)
    72  
    73  	log.Debug("buildrepo.New: profile %q, %q", pro.Peername, pro.ID)
    74  	switch cfg.Repo.Type {
    75  	case "fs":
    76  		if o.Logbook == nil {
    77  			if o.Logbook, err = newLogbook(o.Filesystem, o.Bus, pro, path); err != nil {
    78  				return nil, err
    79  			}
    80  		}
    81  		if o.Dscache == nil {
    82  			if o.Dscache, err = newDscache(ctx, o.Filesystem, o.Bus, o.Logbook, pro.Peername, path); err != nil {
    83  				return nil, err
    84  			}
    85  		}
    86  
    87  		return fsrepo.NewRepo(ctx, path, o.Filesystem, o.Logbook, o.Dscache, o.Profiles, o.Bus)
    88  	case "mem":
    89  		return repo.NewMemRepo(ctx, o.Filesystem, o.Logbook, o.Dscache, o.Profiles, o.Bus)
    90  	default:
    91  		return nil, fmt.Errorf("unknown repo type: %s", cfg.Repo.Type)
    92  	}
    93  }
    94  
    95  // NewFilesystem creates a qfs.Filesystem from configuration
    96  func NewFilesystem(ctx context.Context, cfg *config.Config) (*muxfs.Mux, error) {
    97  	qriPath := filepath.Dir(cfg.Path())
    98  
    99  	for i, fsCfg := range cfg.Filesystems {
   100  		if fsCfg.Type == "ipfs" {
   101  			if path, ok := fsCfg.Config["path"].(string); ok {
   102  				if !filepath.IsAbs(path) {
   103  					// resolve relative filepaths
   104  					cfg.Filesystems[i].Config["path"] = filepath.Join(qriPath, path)
   105  				}
   106  			}
   107  		}
   108  	}
   109  
   110  	if cfg.Repo.Type == "mem" {
   111  		hasMemType := false
   112  		for _, fsCfg := range cfg.Filesystems {
   113  			if fsCfg.Type == "mem" {
   114  				hasMemType = true
   115  			}
   116  		}
   117  		if !hasMemType {
   118  			cfg.Filesystems = append(cfg.Filesystems, qfs.Config{Type: "mem"})
   119  		}
   120  	}
   121  
   122  	return muxfs.New(ctx, cfg.Filesystems)
   123  }
   124  
   125  func newLogbook(fs qfs.Filesystem, bus event.Bus, pro *profile.Profile, repoPath string) (book *logbook.Book, err error) {
   126  	logbookPath := filepath.Join(repoPath, "logbook.qfb")
   127  	return logbook.NewJournal(*pro, bus, fs, logbookPath)
   128  }
   129  
   130  func newDscache(ctx context.Context, fs qfs.Filesystem, bus event.Bus, book *logbook.Book, username, repoPath string) (*dscache.Dscache, error) {
   131  	// This seems to be a bug, the repoPath does not end in "qri" in some tests.
   132  	if !strings.HasSuffix(repoPath, "qri") {
   133  		return nil, fmt.Errorf("invalid repo path: %q", repoPath)
   134  	}
   135  	dscachePath := filepath.Join(repoPath, "dscache.qfb")
   136  	return dscache.NewDscache(ctx, fs, bus, username, dscachePath), nil
   137  }