mirror of
https://github.com/golang/go
synced 2024-11-19 03:14:42 -07:00
ca0407e66b
Eliminate the file watcher, since it led to a lot of confusion and difficulty reasoning about the flow of a file action. This change splits a file invalidation into the two logical steps - 1) things that affect the overlay, and 2) things that affect the view. It is based on top of CL 211757, so the diffs will look better once that CL is merged. Change-Id: I277475569b61f3c80feaa6b6fe457b4bace82e35 Reviewed-on: https://go-review.googlesource.com/c/tools/+/211777 Run-TryBot: Rebecca Stambler <rstambler@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
154 lines
3.5 KiB
Go
154 lines
3.5 KiB
Go
// Copyright 2019 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package cache
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
|
|
"golang.org/x/tools/internal/lsp/source"
|
|
"golang.org/x/tools/internal/span"
|
|
errors "golang.org/x/xerrors"
|
|
)
|
|
|
|
type overlay struct {
|
|
session *session
|
|
uri span.URI
|
|
data []byte
|
|
hash string
|
|
version float64
|
|
kind source.FileKind
|
|
|
|
// sameContentOnDisk is true if a file has been saved on disk,
|
|
// and therefore does not need to be part of the overlay sent to go/packages.
|
|
sameContentOnDisk bool
|
|
}
|
|
|
|
func (o *overlay) FileSystem() source.FileSystem {
|
|
return o.session
|
|
}
|
|
|
|
func (o *overlay) Identity() source.FileIdentity {
|
|
return source.FileIdentity{
|
|
URI: o.uri,
|
|
Identifier: o.hash,
|
|
Version: o.version,
|
|
Kind: o.kind,
|
|
}
|
|
}
|
|
func (o *overlay) Read(ctx context.Context) ([]byte, string, error) {
|
|
return o.data, o.hash, nil
|
|
}
|
|
|
|
func (s *session) setOverlay(uri span.URI, version float64, data []byte) error {
|
|
s.overlayMu.Lock()
|
|
defer s.overlayMu.Unlock()
|
|
|
|
o, ok := s.overlays[uri]
|
|
if !ok {
|
|
return errors.Errorf("setting overlay for unopened file %s", uri)
|
|
}
|
|
s.overlays[uri] = &overlay{
|
|
session: s,
|
|
uri: uri,
|
|
kind: o.kind,
|
|
data: data,
|
|
hash: hashContents(data),
|
|
version: version,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *session) closeOverlay(uri span.URI) error {
|
|
s.openFiles.Delete(uri)
|
|
|
|
s.overlayMu.Lock()
|
|
defer s.overlayMu.Unlock()
|
|
|
|
_, ok := s.overlays[uri]
|
|
if !ok {
|
|
return errors.Errorf("closing unopened overlay %s", uri)
|
|
}
|
|
delete(s.overlays, uri)
|
|
return nil
|
|
}
|
|
|
|
func (s *session) openOverlay(ctx context.Context, uri span.URI, languageID string, version float64, data []byte) error {
|
|
kind := source.DetectLanguage(languageID, uri.Filename())
|
|
if kind == source.UnknownKind {
|
|
return errors.Errorf("openOverlay: unknown file kind for %s", uri)
|
|
}
|
|
|
|
s.openFiles.Store(uri, true)
|
|
|
|
s.overlayMu.Lock()
|
|
defer s.overlayMu.Unlock()
|
|
|
|
s.overlays[uri] = &overlay{
|
|
session: s,
|
|
uri: uri,
|
|
kind: kind,
|
|
data: data,
|
|
hash: hashContents(data),
|
|
version: version,
|
|
}
|
|
// If the file is on disk, check if its content is the same as the overlay.
|
|
if _, hash, err := s.cache.GetFile(uri, kind).Read(ctx); err == nil {
|
|
if hash == s.overlays[uri].hash {
|
|
s.overlays[uri].sameContentOnDisk = true
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *session) saveOverlay(uri span.URI, version float64, data []byte) error {
|
|
s.overlayMu.Lock()
|
|
defer s.overlayMu.Unlock()
|
|
|
|
o, ok := s.overlays[uri]
|
|
if !ok {
|
|
return errors.Errorf("saveOverlay: unopened overlay %s", uri)
|
|
}
|
|
if o.version != version {
|
|
return errors.Errorf("saveOverlay: saving %s at version %v, currently at %v", uri, version, o.version)
|
|
}
|
|
if data != nil {
|
|
if !bytes.Equal(o.data, data) {
|
|
return errors.Errorf("saveOverlay: overlay %s changed on save", uri)
|
|
}
|
|
o.data = data
|
|
}
|
|
o.sameContentOnDisk = true
|
|
o.version = version
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *session) readOverlay(uri span.URI) *overlay {
|
|
s.overlayMu.Lock()
|
|
defer s.overlayMu.Unlock()
|
|
|
|
// We might have the content saved in an overlay.
|
|
if overlay, ok := s.overlays[uri]; ok {
|
|
return overlay
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *session) buildOverlay() map[string][]byte {
|
|
s.overlayMu.Lock()
|
|
defer s.overlayMu.Unlock()
|
|
|
|
overlays := make(map[string][]byte)
|
|
for uri, overlay := range s.overlays {
|
|
// TODO(rstambler): Make sure not to send overlays outside of the current view.
|
|
if overlay.sameContentOnDisk {
|
|
continue
|
|
}
|
|
overlays[uri.Filename()] = overlay.data
|
|
}
|
|
return overlays
|
|
}
|