github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/repo/fs/fs.go (about) 1 // Package fsrepo is a file-system implementation of repo 2 package fsrepo 3 4 import ( 5 "context" 6 "fmt" 7 "os" 8 "sync" 9 10 golog "github.com/ipfs/go-log" 11 "github.com/qri-io/qfs/muxfs" 12 "github.com/qri-io/qri/dscache" 13 "github.com/qri-io/qri/dsref" 14 "github.com/qri-io/qri/event" 15 "github.com/qri-io/qri/logbook" 16 "github.com/qri-io/qri/profile" 17 "github.com/qri-io/qri/repo" 18 reporef "github.com/qri-io/qri/repo/ref" 19 ) 20 21 var log = golog.Logger("fsrepo") 22 23 // Repo is a filesystem-based implementation of the Repo interface 24 type Repo struct { 25 basepath 26 27 repo.Refstore 28 29 bus event.Bus 30 fsys *muxfs.Mux 31 logbook *logbook.Book 32 dscache *dscache.Dscache 33 34 profiles profile.Store 35 36 doneWg sync.WaitGroup 37 doneCh chan struct{} 38 doneErr error 39 } 40 41 var _ repo.Repo = (*Repo)(nil) 42 43 // NewRepo creates a new file-based repository 44 func NewRepo(ctx context.Context, path string, fsys *muxfs.Mux, book *logbook.Book, cache *dscache.Dscache, pro profile.Store, bus event.Bus) (repo.Repo, error) { 45 if err := os.MkdirAll(path, os.ModePerm); err != nil { 46 log.Error(err) 47 return nil, err 48 } 49 bp := basepath(path) 50 51 r := &Repo{ 52 bus: bus, 53 fsys: fsys, 54 basepath: bp, 55 logbook: book, 56 dscache: cache, 57 58 Refstore: Refstore{basepath: bp, file: FileRefs}, 59 profiles: pro, 60 61 doneCh: make(chan struct{}), 62 } 63 64 r.doneWg.Add(1) 65 go func() { 66 <-r.fsys.Done() 67 r.doneErr = r.fsys.DoneErr() 68 r.doneWg.Done() 69 }() 70 71 go func() { 72 r.doneWg.Wait() 73 close(r.doneCh) 74 }() 75 76 if _, err := maybeCreateFlatbufferRefsFile(path); err != nil { 77 return nil, err 78 } 79 80 own := pro.Owner(ctx) 81 // add our own profile to the store if it doesn't already exist. 82 if _, e := r.Profiles().GetProfile(ctx, own.ID); e != nil { 83 if err := r.Profiles().PutProfile(ctx, own); err != nil { 84 return nil, err 85 } 86 } 87 88 return r, nil 89 } 90 91 // ResolveRef implements the dsref.RefResolver interface 92 func (r *Repo) ResolveRef(ctx context.Context, ref *dsref.Ref) (string, error) { 93 if r == nil { 94 return "", dsref.ErrRefNotFound 95 } 96 97 // TODO (b5) - not totally sure why, but memRepo doesn't seem to be wiring up 98 // dscache correctly in in tests 99 // if r.dscache != nil { 100 // return r.dscache.ResolveRef(ctx, ref) 101 // } 102 103 if r.logbook == nil { 104 return "", fmt.Errorf("cannot resolve local references without logbook") 105 } 106 107 if ref.InitID != "" { 108 res, err := r.logbook.Ref(ctx, ref.InitID) 109 if err != nil { 110 return "", err 111 } 112 113 *ref = res 114 return "", nil 115 } 116 117 // Preserve the input ref path, and convert to the old style dataset ref for repo. 118 origPath := ref.Path 119 datasetRef := reporef.DatasetRef{ 120 Peername: ref.Username, 121 Name: ref.Name, 122 } 123 124 // Get the reference from the refstore. This has everything but initID 125 match, err := r.GetRef(datasetRef) 126 if err != nil { 127 return "", dsref.ErrRefNotFound 128 } 129 // Create our resolved reference. If the input ref had a path, reassign that 130 *ref = reporef.ConvertToDsref(match) 131 if origPath != "" { 132 ref.Path = origPath 133 } 134 135 // Get just the initID from logbook 136 ref.InitID, err = r.logbook.RefToInitID(*ref) 137 return "", err 138 } 139 140 // Path returns the path to the root of the repo directory 141 func (r *Repo) Path() string { 142 return string(r.basepath) 143 } 144 145 // Bus accesses the repo's bus 146 func (r *Repo) Bus() event.Bus { 147 return r.bus 148 } 149 150 // Filesystem returns this repo's Filesystem 151 func (r *Repo) Filesystem() *muxfs.Mux { 152 return r.fsys 153 } 154 155 // SetFilesystem implements QFSSetter, currently used during lib contstruction 156 func (r *Repo) SetFilesystem(fs *muxfs.Mux) { 157 r.fsys = fs 158 } 159 160 // Logbook stores operation logs for coordinating state across peers 161 func (r *Repo) Logbook() *logbook.Book { 162 return r.logbook 163 } 164 165 // Dscache returns a dscache 166 func (r *Repo) Dscache() *dscache.Dscache { 167 return r.dscache 168 } 169 170 // Profiles returns this repo's Peers implementation 171 func (r *Repo) Profiles() profile.Store { 172 return r.profiles 173 } 174 175 // Done returns a channel that the repo will send on when the repo is finished 176 // closing 177 func (r *Repo) Done() <-chan struct{} { 178 return r.doneCh 179 } 180 181 // DoneErr gives an error that occurred during the shutdown process 182 func (r *Repo) DoneErr() error { 183 return r.doneErr 184 } 185 186 // Destroy destroys this repository 187 func (r *Repo) Destroy() error { 188 return os.RemoveAll(string(r.basepath)) 189 }