From 6481b583bbd1885789272c9d12cd1f6b18c687b5 Mon Sep 17 00:00:00 2001
From: umbynos <umberto.baldi@edu.unito.it>
Date: Thu, 14 Jan 2021 18:47:24 +0100
Subject: [PATCH 1/2] update doc

---
 docs/tools.md | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/docs/tools.md b/docs/tools.md
index 35be570c9..93ac8e3f8 100644
--- a/docs/tools.md
+++ b/docs/tools.md
@@ -10,7 +10,8 @@
 ```go
 type Tools struct {
 	Directory string
-	IndexURL  string
+    IndexURL  string
+    LastRefresh time.Time
 	Logger    log.StdLogger
 }
 ```
@@ -20,6 +21,7 @@ to download a tool from the arduino servers.
 
 - *Directory* contains the location where the tools are downloaded.
 - *IndexURL* contains the url where the tools description is contained.
+- *LastRefresh* contains the last update time
 - *Logger* is a StdLogger used for reporting debug and info messages
 - *installed* contains a map of the tools and their exact location
 

From 0cb27d8e7a201db4f9fc27bce08a5d6271121fb6 Mon Sep 17 00:00:00 2001
From: umbynos <umberto.baldi@edu.unito.it>
Date: Thu, 14 Jan 2021 18:48:31 +0100
Subject: [PATCH 2/2] add read write mutex synchronization to installed map

---
 tools/download.go |  6 ++++++
 tools/tools.go    | 21 ++++++++++++++++++++-
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/tools/download.go b/tools/download.go
index c5fa4f31f..6c9ced87b 100644
--- a/tools/download.go
+++ b/tools/download.go
@@ -193,10 +193,14 @@ func (t *Tools) Download(pack, name, version, behaviour string) error {
 
 	// Check if it already exists
 	if behaviour == "keep" {
+		t.mutex.RLock()
 		location, ok := t.installed[key]
+		t.mutex.RUnlock()
 		if ok && pathExists(location) {
 			// overwrite the default tool with this one
+			t.mutex.Lock()
 			t.installed[correctTool.Name] = location
+			t.mutex.Unlock()
 			t.Logger("The tool is already present on the system")
 			return t.writeMap()
 		}
@@ -267,8 +271,10 @@ func (t *Tools) Download(pack, name, version, behaviour string) error {
 	// Update the tool map
 	t.Logger("Updating map with location " + location)
 
+	t.mutex.Lock()
 	t.installed[name] = location
 	t.installed[name+"-"+correctTool.Version] = location
+	t.mutex.Unlock()
 	return t.writeMap()
 }
 
diff --git a/tools/tools.go b/tools/tools.go
index 2884325da..88ef425ea 100644
--- a/tools/tools.go
+++ b/tools/tools.go
@@ -9,6 +9,7 @@ import (
 	"path"
 	"path/filepath"
 	"strings"
+	"sync"
 	"time"
 
 	"github.com/xrash/smetrics"
@@ -35,21 +36,30 @@ type Tools struct {
 	LastRefresh time.Time
 	Logger      func(msg string)
 	installed   map[string]string
+	mutex       sync.RWMutex
 }
 
 // Init creates the Installed map and populates it from a file in .arduino-create
 func (t *Tools) Init(APIlevel string) {
 	createDir(t.Directory)
+	t.mutex.Lock()
 	t.installed = make(map[string]string)
+	t.mutex.Unlock()
 	t.readMap()
+	t.mutex.RLock()
 	if t.installed["apilevel"] != APIlevel {
+		t.mutex.RUnlock()
 		// wipe the folder and reinitialize the data
 		os.RemoveAll(t.Directory)
 		createDir(t.Directory)
+		t.mutex.Lock()
 		t.installed = make(map[string]string)
 		t.installed["apilevel"] = APIlevel
+		t.mutex.Unlock()
 		t.writeMap()
 		t.readMap()
+	} else {
+		t.mutex.RUnlock()
 	}
 }
 
@@ -62,13 +72,17 @@ func (t *Tools) GetLocation(command string) (string, error) {
 	var ok bool
 
 	// Load installed
+	t.mutex.RLock()
 	fmt.Println(t.installed)
+	t.mutex.RUnlock()
 
 	err := t.readMap()
 	if err != nil {
 		return "", err
 	}
 
+	t.mutex.RLock()
+	defer t.mutex.RUnlock()
 	fmt.Println(t.installed)
 
 	// use string similarity to resolve a runtime var with a "similar" map element
@@ -82,12 +96,14 @@ func (t *Tools) GetLocation(command string) (string, error) {
 			}
 		}
 	}
-
 	return filepath.ToSlash(location), nil
 }
 
+// writeMap() writes installed map to the json file "installed.json"
 func (t *Tools) writeMap() error {
+	t.mutex.RLock()
 	b, err := json.Marshal(t.installed)
+	t.mutex.RUnlock()
 	if err != nil {
 		return err
 	}
@@ -95,12 +111,15 @@ func (t *Tools) writeMap() error {
 	return ioutil.WriteFile(filePath, b, 0644)
 }
 
+// readMap() reads the installed map from json file "installed.json"
 func (t *Tools) readMap() error {
 	filePath := path.Join(dir(), "installed.json")
 	b, err := ioutil.ReadFile(filePath)
 	if err != nil {
 		return err
 	}
+	t.mutex.Lock()
+	defer t.mutex.Unlock()
 	return json.Unmarshal(b, &t.installed)
 }