Skip to content

Commit 4f358e4

Browse files
committed
make tools.Tools struct properties unexported and use a "constructor/getters"
1 parent 620acfe commit 4f358e4

File tree

3 files changed

+115
-90
lines changed

3 files changed

+115
-90
lines changed

main.go

+7-10
Original file line numberDiff line numberDiff line change
@@ -180,17 +180,14 @@ func loop() {
180180
// Instantiate Index
181181
Index = index.Init(*indexURL, config.GetDataDir())
182182

183-
// Instantiate Tools
184-
Tools = tools.Tools{
185-
Directory: config.GetDataDir().String(),
186-
Index: Index,
187-
Logger: func(msg string) {
188-
mapD := map[string]string{"DownloadStatus": "Pending", "Msg": msg}
189-
mapB, _ := json.Marshal(mapD)
190-
h.broadcastSys <- mapB
191-
},
183+
logger := func(msg string) {
184+
mapD := map[string]string{"DownloadStatus": "Pending", "Msg": msg}
185+
mapB, _ := json.Marshal(mapD)
186+
h.broadcastSys <- mapB
192187
}
193-
Tools.Init()
188+
189+
// Instantiate Tools
190+
Tools = *tools.New(config.GetDataDir(), Index, logger)
194191

195192
// Let's handle the config
196193
configDir := config.GetDefaultConfigDir()

tools/download.go

+20-24
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func pathExists(path string) bool {
7878
// if it already exists.
7979
func (t *Tools) Download(pack, name, version, behaviour string) error {
8080

81-
body, err := t.Index.Read()
81+
body, err := t.getIndex().Read()
8282
if err != nil {
8383
return err
8484
}
@@ -90,29 +90,25 @@ func (t *Tools) Download(pack, name, version, behaviour string) error {
9090
correctTool, correctSystem := findTool(pack, name, version, data)
9191

9292
if correctTool.Name == "" || correctSystem.URL == "" {
93-
t.Logger("We couldn't find a tool with the name " + name + " and version " + version + " packaged by " + pack)
93+
t.loggerPrint("We couldn't find a tool with the name " + name + " and version " + version + " packaged by " + pack)
9494
return nil
9595
}
9696

9797
key := correctTool.Name + "-" + correctTool.Version
9898

9999
// Check if it already exists
100100
if behaviour == "keep" {
101-
t.mutex.RLock()
102-
location, ok := t.installed[key]
103-
t.mutex.RUnlock()
101+
location, ok := t.getMapValue(key)
104102
if ok && pathExists(location) {
105103
// overwrite the default tool with this one
106-
t.mutex.Lock()
107-
t.installed[correctTool.Name] = location
108-
t.mutex.Unlock()
109-
t.Logger("The tool is already present on the system")
104+
t.setMapValue(correctTool.Name, location)
105+
t.loggerPrint("The tool is already present on the system")
110106
return t.writeMap()
111107
}
112108
}
113109

114110
// Download the tool
115-
t.Logger("Downloading tool " + name + " from " + correctSystem.URL)
111+
t.loggerPrint("Downloading tool " + name + " from " + correctSystem.URL)
116112
resp, err := http.Get(correctSystem.URL)
117113
if err != nil {
118114
return err
@@ -134,9 +130,11 @@ func (t *Tools) Download(pack, name, version, behaviour string) error {
134130
}
135131

136132
// Decompress
137-
t.Logger("Unpacking tool " + name)
133+
t.loggerPrint("Unpacking tool " + name)
138134

139-
location := path.Join(dir(), pack, correctTool.Name, correctTool.Version)
135+
configDir := t.getDirectory()
136+
137+
location := configDir.Join(pack, correctTool.Name, correctTool.Version).String()
140138
err = os.RemoveAll(location)
141139

142140
if err != nil {
@@ -150,18 +148,18 @@ func (t *Tools) Download(pack, name, version, behaviour string) error {
150148

151149
switch srcType {
152150
case "application/zip":
153-
location, err = extractZip(t.Logger, body, location)
151+
location, err = extractZip(t.getLogger(), body, location)
154152
case "application/x-bz2":
155153
case "application/octet-stream":
156-
location, err = extractBz2(t.Logger, body, location)
154+
location, err = extractBz2(t.getLogger(), body, location)
157155
case "application/x-gzip":
158-
location, err = extractTarGz(t.Logger, body, location)
156+
location, err = extractTarGz(t.getLogger(), body, location)
159157
default:
160158
return errors.New("Unknown extension for file " + correctSystem.URL)
161159
}
162160

163161
if err != nil {
164-
t.Logger("Error extracting the archive: " + err.Error())
162+
t.loggerPrint("Error extracting the archive: " + err.Error())
165163
return err
166164
}
167165

@@ -171,15 +169,13 @@ func (t *Tools) Download(pack, name, version, behaviour string) error {
171169
}
172170

173171
// Ensure that the files are executable
174-
t.Logger("Ensure that the files are executable")
172+
t.loggerPrint("Ensure that the files are executable")
175173

176174
// Update the tool map
177-
t.Logger("Updating map with location " + location)
175+
t.loggerPrint("Updating map with location " + location)
178176

179-
t.mutex.Lock()
180-
t.installed[name] = location
181-
t.installed[name+"-"+correctTool.Version] = location
182-
t.mutex.Unlock()
177+
t.setMapValue(name, location)
178+
t.setMapValue(name+"-"+correctTool.Version, location)
183179
return t.writeMap()
184180
}
185181

@@ -475,11 +471,11 @@ func (t *Tools) installDrivers(location string) error {
475471
preamble = "./"
476472
}
477473
if _, err := os.Stat(filepath.Join(location, "post_install"+extension)); err == nil {
478-
t.Logger("Installing drivers")
474+
t.loggerPrint("Installing drivers")
479475
ok := MessageBox("Installing drivers", "We are about to install some drivers needed to use Arduino/Genuino boards\nDo you want to continue?")
480476
if ok == OkPressed {
481477
os.Chdir(location)
482-
t.Logger(preamble + "post_install" + extension)
478+
t.loggerPrint(preamble + "post_install" + extension)
483479
oscmd := exec.Command(preamble + "post_install" + extension)
484480
if OS != "linux" {
485481
// spawning a shell could be the only way to let the user type his password

tools/tools.go

+88-56
Original file line numberDiff line numberDiff line change
@@ -18,48 +18,111 @@ package tools
1818
import (
1919
"encoding/json"
2020
"fmt"
21-
"os"
22-
"os/user"
23-
"path"
2421
"path/filepath"
2522
"strings"
2623
"sync"
2724

2825
"github.com/arduino/arduino-create-agent/index"
26+
"github.com/arduino/go-paths-helper"
2927
"github.com/xrash/smetrics"
3028
)
3129

3230
// Tools handle the tools necessary for an upload on a board.
3331
// It provides a means to download a tool from the arduino servers.
3432
//
35-
// - *Directory* contains the location where the tools are downloaded.
36-
// - *IndexURL* contains the url where the tools description is contained.
37-
// - *Logger* is a StdLogger used for reporting debug and info messages
38-
// - *installed* contains a map of the tools and their exact location
33+
// - *directory* contains the location where the tools are downloaded.
34+
// - *indexURL* contains the url where the tools description is contained.
35+
// - *logger* is a StdLogger used for reporting debug and info messages
36+
// - *installed* contains a map[string]string of the tools installed and their exact location
3937
//
4038
// Usage:
41-
// You have to instantiate the struct by passing it the required parameters:
42-
// _tools := tools.Tools{
43-
// Directory: "/home/user/.arduino-create",
44-
// IndexURL: "https://downloads.arduino.cc/packages/package_index.json"
45-
// Logger: log.Logger
46-
// }
39+
// You have to call the New() function passing it the required parameters:
40+
//
41+
// index = index.Init("https://downloads.arduino.cc/packages/package_staging_index.json", dataDir)
42+
// tools := tools.New(dataDir, index, logger)
4743

4844
// Tools will represent the installed tools
4945
type Tools struct {
50-
Directory string
51-
Index *index.Resource
52-
Logger func(msg string)
46+
directory *paths.Path
47+
index *index.Resource
48+
logger func(msg string)
5349
installed map[string]string
5450
mutex sync.RWMutex
5551
}
5652

57-
// Init creates the Installed map and populates it from a file in .arduino-create
58-
func (t *Tools) Init() {
53+
// New will return a Tool object, allowing the caller to execute operations on it.
54+
// The New functions accept the directory to use to host the tools,
55+
// an index (used to download the tools),
56+
// and a logger to log the operations
57+
func New(directory *paths.Path, index *index.Resource, logger func(msg string)) *Tools {
58+
t := &Tools{
59+
directory: directory,
60+
index: index,
61+
logger: logger,
62+
installed: map[string]string{},
63+
mutex: sync.RWMutex{},
64+
}
65+
_ = t.readMap()
66+
return t
67+
}
68+
69+
func (t *Tools) getIndex() *index.Resource {
70+
return t.index
71+
}
72+
73+
func (t *Tools) loggerPrint(msg string) {
74+
t.logger(msg)
75+
}
76+
77+
func (t *Tools) getLogger() func(msg string) {
78+
return t.logger
79+
}
80+
81+
func (t *Tools) getDirectory() *paths.Path {
82+
return t.directory
83+
}
84+
85+
func (t *Tools) setMapValue(key, value string) {
5986
t.mutex.Lock()
60-
t.installed = make(map[string]string)
87+
t.installed[key] = value
6188
t.mutex.Unlock()
62-
t.readMap()
89+
}
90+
91+
func (t *Tools) getMapValue(key string) (string, bool) {
92+
t.mutex.RLock()
93+
defer t.mutex.RUnlock()
94+
value, ok := t.installed[key]
95+
return value, ok
96+
}
97+
98+
func (t *Tools) printMap() {
99+
t.mutex.RLock()
100+
fmt.Println(t.installed)
101+
t.mutex.RUnlock()
102+
}
103+
104+
// writeMap() writes installed map to the json file "installed.json"
105+
func (t *Tools) writeMap() error {
106+
t.mutex.RLock()
107+
defer t.mutex.RUnlock()
108+
b, err := json.Marshal(t.installed)
109+
if err != nil {
110+
return err
111+
}
112+
filePath := t.getDirectory().Join("installed.json")
113+
return filePath.WriteFile(b)
114+
}
115+
116+
// readMap() reads the installed map from json file "installed.json"
117+
func (t *Tools) readMap() error {
118+
t.mutex.Lock()
119+
defer t.mutex.Unlock()
120+
filePath := t.getDirectory().Join("installed.json")
121+
b, err := filePath.ReadFile()
122+
if err != nil {
123+
return err
124+
}
125+
return json.Unmarshal(b, &t.installed)
63126
}
64127

65128
// GetLocation extracts the toolname from a command like
@@ -71,22 +134,20 @@ func (t *Tools) GetLocation(command string) (string, error) {
71134
var ok bool
72135

73136
// Load installed
74-
t.mutex.RLock()
75-
fmt.Println(t.installed)
76-
t.mutex.RUnlock()
137+
t.printMap()
77138

78139
err := t.readMap()
79140
if err != nil {
80141
return "", err
81142
}
82143

83-
t.mutex.RLock()
84-
defer t.mutex.RUnlock()
85-
fmt.Println(t.installed)
144+
t.printMap()
86145

87146
// use string similarity to resolve a runtime var with a "similar" map element
88-
if location, ok = t.installed[command]; !ok {
147+
if location, ok = t.getMapValue(command); !ok {
89148
maxSimilarity := 0.0
149+
t.mutex.RLock()
150+
defer t.mutex.RUnlock()
90151
for i, candidate := range t.installed {
91152
similarity := smetrics.Jaro(command, i)
92153
if similarity > 0.8 && similarity > maxSimilarity {
@@ -97,32 +158,3 @@ func (t *Tools) GetLocation(command string) (string, error) {
97158
}
98159
return filepath.ToSlash(location), nil
99160
}
100-
101-
// writeMap() writes installed map to the json file "installed.json"
102-
func (t *Tools) writeMap() error {
103-
t.mutex.Lock()
104-
b, err := json.Marshal(t.installed)
105-
defer t.mutex.Unlock()
106-
if err != nil {
107-
return err
108-
}
109-
filePath := path.Join(dir(), "installed.json")
110-
return os.WriteFile(filePath, b, 0644)
111-
}
112-
113-
// readMap() reads the installed map from json file "installed.json"
114-
func (t *Tools) readMap() error {
115-
t.mutex.Lock()
116-
defer t.mutex.Unlock()
117-
filePath := path.Join(dir(), "installed.json")
118-
b, err := os.ReadFile(filePath)
119-
if err != nil {
120-
return err
121-
}
122-
return json.Unmarshal(b, &t.installed)
123-
}
124-
125-
func dir() string {
126-
usr, _ := user.Current()
127-
return path.Join(usr.HomeDir, ".arduino-create")
128-
}

0 commit comments

Comments
 (0)