Skip to content

Fix temp file cleanup and reorganized temp dir structure #154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 45 additions & 14 deletions ls/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"io"
"log"
"os"
"os/exec"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -50,8 +51,10 @@ type INOLanguageServer struct {

progressHandler *progressProxyHandler
closing chan bool
removeTempMutex sync.Mutex
clangdStarted *sync.Cond
dataMux sync.RWMutex
tempDir *paths.Path
buildPath *paths.Path
buildSketchRoot *paths.Path
buildSketchCpp *paths.Path
Expand Down Expand Up @@ -144,18 +147,21 @@ func NewINOLanguageServer(stdin io.Reader, stdout io.Writer, config *Config) *IN
if tmp, err := paths.MkTempDir("", "arduino-language-server"); err != nil {
log.Fatalf("Could not create temp folder: %s", err)
} else {
ls.buildPath = tmp.Canonical()
ls.buildSketchRoot = ls.buildPath.Join("sketch")
ls.tempDir = tmp.Canonical()
}

if tmp, err := paths.MkTempDir("", "arduino-language-server"); err != nil {
ls.buildPath = ls.tempDir.Join("build")
ls.buildSketchRoot = ls.buildPath.Join("sketch")
if err := ls.buildPath.MkdirAll(); err != nil {
log.Fatalf("Could not create temp folder: %s", err)
}
ls.fullBuildPath = ls.tempDir.Join("fullbuild")
if err := ls.fullBuildPath.MkdirAll(); err != nil {
log.Fatalf("Could not create temp folder: %s", err)
} else {
ls.fullBuildPath = tmp.Canonical()
}

logger.Logf("Initial board configuration: %s", ls.config.Fqbn)
logger.Logf("%s", globals.VersionInfo.String())
logger.Logf("Language server temp directory: %s", ls.tempDir)
logger.Logf("Language server build path: %s", ls.buildPath)
logger.Logf("Language server build sketch root: %s", ls.buildSketchRoot)
logger.Logf("Language server FULL build path: %s", ls.fullBuildPath)
Expand Down Expand Up @@ -387,6 +393,7 @@ func (ls *INOLanguageServer) shutdownReqFromIDE(ctx context.Context, logger json
close(done)
}()
_, _ = ls.Clangd.conn.Shutdown(context.Background())
ls.removeTemporaryFiles(logger)
<-done
return nil
}
Expand Down Expand Up @@ -1371,6 +1378,38 @@ func (ls *INOLanguageServer) setTraceNotifFromIDE(logger jsonrpc.FunctionLogger,
ls.Clangd.conn.SetTrace(params)
}

func (ls *INOLanguageServer) removeTemporaryFiles(logger jsonrpc.FunctionLogger) {
ls.removeTempMutex.Lock()
defer ls.removeTempMutex.Unlock()

if ls.tempDir == nil {
// Nothing to remove
return
}

// Start a detached process to remove the temp files
cwd, err := os.Getwd()
if err != nil {
logger.Logf("Error getting current working directory: %s", err)
return
}
cmd := exec.Command(os.Args[0], "remove-temp-files", ls.tempDir.String())
cmd.Dir = cwd
if err := cmd.Start(); err != nil {
logger.Logf("Error starting remove-temp-files process: %s", err)
return
}

// The process is now started, we can reset the paths
ls.buildPath, ls.fullBuildPath, ls.buildSketchRoot, ls.tempDir = nil, nil, nil, nil

// Detach the process so it can continue running even if the parent process exits
if err := cmd.Process.Release(); err != nil {
logger.Logf("Error detaching remove-temp-files process: %s", err)
return
}
}

// Close closes all the json-rpc connections and clean-up temp folders.
func (ls *INOLanguageServer) Close() {
if ls.Clangd != nil {
Expand All @@ -1381,14 +1420,6 @@ func (ls *INOLanguageServer) Close() {
close(ls.closing)
ls.closing = nil
}
if ls.buildPath != nil {
ls.buildPath.RemoveAll()
ls.buildPath = nil
}
if ls.fullBuildPath != nil {
ls.fullBuildPath.RemoveAll()
ls.fullBuildPath = nil
}
}

// CloseNotify returns a channel that is closed when the InoHandler is closed
Expand Down
7 changes: 6 additions & 1 deletion ls/lsp_client_clangd.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ func newClangdLSPClient(logger jsonrpc.FunctionLogger, dataFolder *paths.Path, l
logger.Logf(" Starting clangd: %s", strings.Join(args, " "))
var clangdStdin io.WriteCloser
var clangdStdout, clangdStderr io.ReadCloser
if clangdCmd, err := executils.NewProcess(nil, args...); err != nil {
var extraEnv []string
if ls.tempDir != nil {
extraEnv = append(extraEnv, "TMPDIR="+ls.tempDir.String()) // For unix-based systems
extraEnv = append(extraEnv, "TMP="+ls.tempDir.String()) // For Windows
}
if clangdCmd, err := executils.NewProcess(extraEnv, args...); err != nil {
panic("starting clangd: " + err.Error())
} else if cin, err := clangdCmd.StdinPipe(); err != nil {
panic("getting clangd stdin: " + err.Error())
Expand Down
2 changes: 0 additions & 2 deletions ls/lsp_server_ide.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,6 @@ func (server *IDELSPServer) WorkspaceDidChangeConfiguration(logger jsonrpc.Funct
//
// Since ALS doesn’t have any workspace configuration yet,
// ignore it.
return

}

// WorkspaceDidChangeWatchedFiles is not implemented
Expand Down
14 changes: 14 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"os/signal"
"os/user"
"path"
"strings"

"github.com/arduino/arduino-language-server/ls"
"github.com/arduino/arduino-language-server/streams"
Expand All @@ -20,6 +21,19 @@ import (
)

func main() {
if len(os.Args) > 1 && os.Args[1] == "remove-temp-files" {
for _, tmpFile := range os.Args[2:] {
// SAFETY CHECK
if !strings.Contains(tmpFile, "arduino-language-server") {
fmt.Println("Could not remove extraneous temp folder:", tmpFile)
os.Exit(1)
}

paths.New(tmpFile).RemoveAll()
}
return
}

clangdPath := flag.String(
"clangd", "",
"Path to clangd executable")
Expand Down