aboutsummaryrefslogtreecommitdiff
path: root/internal/lsp/fake/workdir.go
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@google.com>2022-03-29 00:50:59 -0700
committerDan Willemsen <dwillemsen@google.com>2022-03-29 00:52:27 -0700
commitf10932f763d058b0dcb3acfb795c869996fef47b (patch)
tree7e04d345c214f3efac3c4b86c7ec3e831c500437 /internal/lsp/fake/workdir.go
parentd6d1ab63f7e2d16fb9a1f1d29755d12da90aa0bb (diff)
parente693fb417253d14786976bd29a456961aa8b6343 (diff)
downloadgolang-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.go49
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) {