diff options
author | Dan Willemsen <dwillemsen@google.com> | 2022-03-29 00:50:59 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@google.com> | 2022-03-29 00:52:27 -0700 |
commit | f10932f763d058b0dcb3acfb795c869996fef47b (patch) | |
tree | 7e04d345c214f3efac3c4b86c7ec3e831c500437 /internal/lsp/fake/workdir.go | |
parent | d6d1ab63f7e2d16fb9a1f1d29755d12da90aa0bb (diff) | |
parent | e693fb417253d14786976bd29a456961aa8b6343 (diff) | |
download | golang-x-tools-f10932f763d058b0dcb3acfb795c869996fef47b.tar.gz |
Merge commit 'e693fb417253d14786976bd29a456961aa8b6343'
Change-Id: I65e50880732e718fa2264e47ef7cc19e37cc2f05
Diffstat (limited to 'internal/lsp/fake/workdir.go')
-rw-r--r-- | internal/lsp/fake/workdir.go | 49 |
1 files changed, 32 insertions, 17 deletions
diff --git a/internal/lsp/fake/workdir.go b/internal/lsp/fake/workdir.go index d836debd8..0be1d8fdf 100644 --- a/internal/lsp/fake/workdir.go +++ b/internal/lsp/fake/workdir.go @@ -12,8 +12,10 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "strings" "sync" + "time" "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/span" @@ -49,16 +51,6 @@ func (r RelativeTo) RelPath(fp string) string { return filepath.ToSlash(fp) } -func writeTxtar(txt string, rel RelativeTo) error { - files := UnpackTxt(txt) - for name, data := range files { - if err := WriteFileData(name, data, rel); err != nil { - return errors.Errorf("writing to workdir: %w", err) - } - } - return nil -} - // WriteFileData writes content to the relative path, replacing the special // token $SANDBOX_WORKDIR with the relative root given by rel. func WriteFileData(path string, content []byte, rel RelativeTo) error { @@ -67,12 +59,25 @@ func WriteFileData(path string, content []byte, rel RelativeTo) error { if err := os.MkdirAll(filepath.Dir(fp), 0755); err != nil { return errors.Errorf("creating nested directory: %w", err) } - if err := ioutil.WriteFile(fp, []byte(content), 0644); err != nil { - return errors.Errorf("writing %q: %w", path, err) + backoff := 1 * time.Millisecond + for { + err := ioutil.WriteFile(fp, []byte(content), 0644) + if err != nil { + if isWindowsErrLockViolation(err) { + time.Sleep(backoff) + backoff *= 2 + continue + } + return errors.Errorf("writing %q: %w", path, err) + } + return nil } - return nil } +// isWindowsErrLockViolation reports whether err is ERROR_LOCK_VIOLATION +// on Windows. +var isWindowsErrLockViolation = func(err error) bool { return false } + // Workdir is a temporary working directory for tests. It exposes file // operations in terms of relative paths, and fakes file watching by triggering // events on file operations. @@ -138,11 +143,21 @@ func toURI(fp string) protocol.DocumentURI { // ReadFile reads a text file specified by a workdir-relative path. func (w *Workdir) ReadFile(path string) (string, error) { - b, err := ioutil.ReadFile(w.AbsPath(path)) - if err != nil { - return "", err + backoff := 1 * time.Millisecond + for { + b, err := ioutil.ReadFile(w.AbsPath(path)) + if err != nil { + if runtime.GOOS == "plan9" && strings.HasSuffix(err.Error(), " exclusive use file already open") { + // Plan 9 enforces exclusive access to locked files. + // Give the owner time to unlock it and retry. + time.Sleep(backoff) + backoff *= 2 + continue + } + return "", err + } + return string(b), nil } - return string(b), nil } func (w *Workdir) RegexpRange(path, re string) (Pos, Pos, error) { |