diff --git a/internal/lsp/fake/workdir.go b/internal/lsp/fake/workdir.go index d836debd81..c95fbe7165 100644 --- a/internal/lsp/fake/workdir.go +++ b/internal/lsp/fake/workdir.go @@ -14,6 +14,7 @@ import ( "path/filepath" "strings" "sync" + "time" "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/span" @@ -67,12 +68,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. diff --git a/internal/lsp/fake/workdir_windows.go b/internal/lsp/fake/workdir_windows.go new file mode 100644 index 0000000000..ed2b4bb36f --- /dev/null +++ b/internal/lsp/fake/workdir_windows.go @@ -0,0 +1,20 @@ +// Copyright 2021 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 fake + +import ( + "syscall" + + errors "golang.org/x/xerrors" +) + +func init() { + // from https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- + const ERROR_LOCK_VIOLATION syscall.Errno = 33 + + isWindowsErrLockViolation = func(err error) bool { + return errors.Is(err, ERROR_LOCK_VIOLATION) + } +}