Skip to content

Commit 9c3912a

Browse files
committed
Factored some of the checks in LibrariesManager.InstallPrerequisiteCheck
They were duplicated and spread around all the library install functions.
1 parent 51387c4 commit 9c3912a

File tree

2 files changed

+92
-116
lines changed

2 files changed

+92
-116
lines changed

Diff for: arduino/libraries/librariesmanager/install.go

+72-78
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ package librariesmanager
1717

1818
import (
1919
"context"
20-
"errors"
2120
"fmt"
2221
"net/url"
2322
"os"
@@ -35,66 +34,83 @@ import (
3534
"gopkg.in/src-d/go-git.v4/plumbing"
3635
)
3736

38-
type alreadyInstalledError struct{}
37+
// LibraryInstallPlan contains the main information required to perform a library
38+
// install, like the path where the library should be installed and the library
39+
// that is going to be replaced by the new one.
40+
// This is the result of a call to InstallPrerequisiteCheck.
41+
type LibraryInstallPlan struct {
42+
// TargetPath is the path where the library should be installed.
43+
TargetPath *paths.Path
3944

40-
func (e *alreadyInstalledError) Error() string {
41-
return tr("library already installed")
42-
}
45+
// ReplacedLib is the library that is going to be replaced by the new one.
46+
ReplacedLib *libraries.Library
4347

44-
var (
45-
// ErrAlreadyInstalled is returned when a library is already installed and task
46-
// cannot proceed.
47-
ErrAlreadyInstalled = &alreadyInstalledError{}
48-
)
48+
// UpToDate is true if the library to install has the same version of the library we are going to replace.
49+
UpToDate bool
50+
}
4951

5052
// InstallPrerequisiteCheck performs prequisite checks to install a library. It returns the
5153
// install path, where the library should be installed and the possible library that is already
5254
// installed on the same folder and it's going to be replaced by the new one.
53-
func (lm *LibrariesManager) InstallPrerequisiteCheck(name string, version *semver.Version, installLocation libraries.LibraryLocation) (*paths.Path, *libraries.Library, error) {
55+
func (lm *LibrariesManager) InstallPrerequisiteCheck(name string, version *semver.Version, installLocation libraries.LibraryLocation) (*LibraryInstallPlan, error) {
5456
installDir := lm.getLibrariesDir(installLocation)
5557
if installDir == nil {
5658
if installLocation == libraries.User {
57-
return nil, nil, fmt.Errorf(tr("User directory not set"))
59+
return nil, fmt.Errorf(tr("User directory not set"))
5860
}
59-
return nil, nil, fmt.Errorf(tr("Builtin libraries directory not set"))
61+
return nil, fmt.Errorf(tr("Builtin libraries directory not set"))
6062
}
6163

6264
libs := lm.FindByReference(&librariesindex.Reference{Name: name}, installLocation)
63-
for _, lib := range libs {
64-
if lib.Version != nil && lib.Version.Equal(version) {
65-
return lib.InstallDir, nil, ErrAlreadyInstalled
66-
}
67-
}
6865

6966
if len(libs) > 1 {
7067
libsDir := paths.NewPathList()
7168
for _, lib := range libs {
7269
libsDir.Add(lib.InstallDir)
7370
}
74-
return nil, nil, &arduino.MultipleLibraryInstallDetected{
71+
return nil, &arduino.MultipleLibraryInstallDetected{
7572
LibName: name,
7673
LibsDir: libsDir,
7774
Message: tr("Automatic library install can't be performed in this case, please manually remove all duplicates and retry."),
7875
}
7976
}
8077

8178
var replaced *libraries.Library
79+
var upToDate bool
8280
if len(libs) == 1 {
83-
replaced = libs[0]
81+
lib := libs[0]
82+
replaced = lib
83+
upToDate = lib.Version != nil && lib.Version.Equal(version)
8484
}
8585

8686
libPath := installDir.Join(utils.SanitizeName(name))
87-
if replaced != nil && replaced.InstallDir.EquivalentTo(libPath) {
88-
return libPath, replaced, nil
89-
} else if libPath.IsDir() {
90-
return nil, nil, fmt.Errorf(tr("destination dir %s already exists, cannot install"), libPath)
87+
if libPath.IsDir() {
88+
if replaced == nil || !replaced.InstallDir.EquivalentTo(libPath) {
89+
return nil, fmt.Errorf(tr("destination dir %s already exists, cannot install"), libPath)
90+
}
9191
}
92-
return libPath, replaced, nil
92+
93+
return &LibraryInstallPlan{
94+
TargetPath: libPath,
95+
ReplacedLib: replaced,
96+
UpToDate: upToDate,
97+
}, nil
9398
}
9499

95100
// Install installs a library on the specified path.
96-
func (lm *LibrariesManager) Install(indexLibrary *librariesindex.Release, libPath *paths.Path) error {
97-
return indexLibrary.Resource.Install(lm.DownloadsDir, libPath.Parent(), libPath)
101+
func (lm *LibrariesManager) Install(indexLibrary *librariesindex.Release, installPath *paths.Path) error {
102+
return indexLibrary.Resource.Install(lm.DownloadsDir, installPath.Parent(), installPath)
103+
}
104+
105+
// InstallLibraryFromFolder installs a library by copying it from the given folder.
106+
func (lm *LibrariesManager) InstallLibraryFromFolder(libPath *paths.Path, installPath *paths.Path) error {
107+
if installPath.Exist() {
108+
return fmt.Errorf("%s: %s", tr("destination directory already exists"), installPath)
109+
}
110+
if err := libPath.CopyDirTo(installPath); err != nil {
111+
return fmt.Errorf("%s: %w", tr("copying library to destination directory:"), err)
112+
}
113+
return nil
98114
}
99115

100116
// Uninstall removes a Library
@@ -103,7 +119,7 @@ func (lm *LibrariesManager) Uninstall(lib *libraries.Library) error {
103119
return fmt.Errorf(tr("install directory not set"))
104120
}
105121
if err := lib.InstallDir.RemoveAll(); err != nil {
106-
return fmt.Errorf(tr("removing lib directory: %s"), err)
122+
return fmt.Errorf(tr("removing library directory: %s"), err)
107123
}
108124

109125
alternatives := lm.Libraries[lib.Name]
@@ -160,41 +176,29 @@ func (lm *LibrariesManager) InstallZipLib(ctx context.Context, archivePath *path
160176
return err
161177
}
162178

163-
// Check if the library is already installed and determine install path
164-
var installPath *paths.Path
165-
libInstalled, libReplaced, err := lm.InstallPrerequisiteCheck(library.Name, library.Version, libraries.User)
166-
if errors.Is(err, ErrAlreadyInstalled) {
179+
// Check if the library is already installed
180+
installPlan, err := lm.InstallPrerequisiteCheck(library.Name, library.Version, libraries.User)
181+
if err != nil {
182+
return err
183+
}
184+
if installPlan.UpToDate {
167185
if !overwrite {
168186
return fmt.Errorf(tr("library %s already installed"), library.Name)
169187
}
170-
installPath = libInstalled
171-
} else if err != nil {
172-
return err
173-
} else if libReplaced != nil {
188+
}
189+
190+
// Remove the old library if present
191+
if installPlan.ReplacedLib != nil {
174192
if !overwrite {
175-
return fmt.Errorf(tr("Library %[1]s is already installed, but with a different version: %[2]s", library.Name, libReplaced))
193+
return fmt.Errorf(tr("Library %[1]s is already installed, but with a different version: %[2]s", library.Name, installPlan.ReplacedLib))
176194
}
177-
installPath = libReplaced.InstallDir
178-
} else {
179-
installPath = installDir.Join(library.Name)
180-
if !overwrite && installPath.IsDir() {
181-
return fmt.Errorf(tr("library %s already installed", library.Name))
195+
if err := lm.Uninstall(installPlan.ReplacedLib); err != nil {
196+
return err
182197
}
183198
}
184199

185-
// Deletes libraries folder if already installed
186-
if installPath.IsDir() {
187-
installPath.RemoveAll()
188-
}
189-
if installPath.Exist() {
190-
return fmt.Errorf(tr("could not create directory %s: a file with the same name exists!", installPath))
191-
}
192-
193-
// Copy extracted library in the destination directory
194-
if err := installDir.MkdirAll(); err != nil {
195-
return err
196-
}
197-
if err := tmpInstallPath.CopyDirTo(installPath); err != nil {
200+
// Install extracted library in the destination directory
201+
if err := lm.InstallLibraryFromFolder(tmpInstallPath, installPlan.TargetPath); err != nil {
198202
return fmt.Errorf(tr("moving extracted archive to destination dir: %s"), err)
199203
}
200204

@@ -257,39 +261,29 @@ func (lm *LibrariesManager) InstallGitLib(gitURL string, overwrite bool) error {
257261
}
258262

259263
// Check if the library is already installed and determine install path
260-
var installPath *paths.Path
261-
libInstalled, libReplaced, err := lm.InstallPrerequisiteCheck(library.Name, library.Version, libraries.User)
262-
if errors.Is(err, ErrAlreadyInstalled) {
264+
installPlan, err := lm.InstallPrerequisiteCheck(library.Name, library.Version, libraries.User)
265+
if err != nil {
266+
return err
267+
}
268+
if installPlan.UpToDate {
263269
if !overwrite {
264270
return fmt.Errorf(tr("library %s already installed"), library.Name)
265271
}
266-
installPath = libInstalled
267-
} else if err != nil {
268-
return err
269-
} else if libReplaced != nil {
272+
}
273+
if installPlan.ReplacedLib != nil {
270274
if !overwrite {
271-
return fmt.Errorf(tr("Library %[1]s is already installed, but with a different version: %[2]s", library.Name, libReplaced))
275+
return fmt.Errorf(tr("Library %[1]s is already installed, but with a different version: %[2]s", library.Name, installPlan.ReplacedLib))
272276
}
273-
installPath = libReplaced.InstallDir
274-
} else {
275-
installPath = installDir.Join(library.Name)
276-
if !overwrite && installPath.IsDir() {
277-
return fmt.Errorf(tr("library %s already installed", library.Name))
277+
if err := lm.Uninstall(installPlan.ReplacedLib); err != nil {
278+
return err
278279
}
279280
}
280281

281-
// Deletes libraries folder if already installed
282-
if installPath.IsDir() {
283-
installPath.RemoveAll()
284-
}
285-
if installPath.Exist() {
286-
return fmt.Errorf(tr("could not create directory %s: a file with the same name exists!", installPath))
287-
}
288-
289-
// Copy extracted library in the destination directory
290-
if err := tmpInstallPath.CopyDirTo(installPath); err != nil {
282+
// Install extracted library in the destination directory
283+
if err := lm.InstallLibraryFromFolder(tmpInstallPath, installPlan.TargetPath); err != nil {
291284
return fmt.Errorf(tr("moving extracted archive to destination dir: %s"), err)
292285
}
286+
293287
return nil
294288
}
295289

Diff for: commands/lib/install.go

+20-38
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func LibraryInstall(ctx context.Context, req *rpc.LibraryInstallRequest, downloa
6868
}
6969

7070
// Find the libReleasesToInstall to install
71-
libReleasesToInstall := []*librariesindex.Release{}
71+
libReleasesToInstall := map[*librariesindex.Release]*librariesmanager.LibraryInstallPlan{}
7272
for _, lib := range toInstall {
7373
libRelease, err := findLibraryIndexRelease(lm, &rpc.LibraryInstallRequest{
7474
Name: lib.Name,
@@ -77,8 +77,9 @@ func LibraryInstall(ctx context.Context, req *rpc.LibraryInstallRequest, downloa
7777
if err != nil {
7878
return err
7979
}
80-
_, libReplaced, err := lm.InstallPrerequisiteCheck(libRelease.Library.Name, libRelease.Version, installLocation)
81-
if errors.Is(err, librariesmanager.ErrAlreadyInstalled) {
80+
81+
installTask, err := lm.InstallPrerequisiteCheck(libRelease.Library.Name, libRelease.Version, installLocation)
82+
if installTask.UpToDate {
8283
taskCB(&rpc.TaskProgress{Message: tr("Already installed %s", libRelease), Completed: true})
8384
continue
8485
}
@@ -87,63 +88,44 @@ func LibraryInstall(ctx context.Context, req *rpc.LibraryInstallRequest, downloa
8788
}
8889

8990
if req.GetNoOverwrite() {
90-
if libReplaced != nil {
91-
return fmt.Errorf(tr("Library %[1]s is already installed, but with a different version: %[2]s", libRelease, libReplaced))
91+
if installTask.ReplacedLib != nil {
92+
return fmt.Errorf(tr("Library %[1]s is already installed, but with a different version: %[2]s", libRelease, installTask.ReplacedLib))
9293
}
9394
}
94-
libReleasesToInstall = append(libReleasesToInstall, libRelease)
95+
libReleasesToInstall[libRelease] = installTask
9596
}
9697

97-
didInstall := false
98-
for _, libRelease := range libReleasesToInstall {
98+
for libRelease, installTask := range libReleasesToInstall {
9999
if err := downloadLibrary(lm, libRelease, downloadCB, taskCB); err != nil {
100100
return err
101101
}
102-
103-
if err := installLibrary(lm, libRelease, installLocation, taskCB); err != nil {
104-
if errors.Is(err, librariesmanager.ErrAlreadyInstalled) {
105-
continue
106-
} else {
107-
return err
108-
}
102+
if err := installLibrary(lm, libRelease, installTask, taskCB); err != nil {
103+
return err
109104
}
110-
didInstall = true
111105
}
112106

113-
if didInstall {
114-
if err := commands.Init(&rpc.InitRequest{Instance: req.Instance}, nil); err != nil {
115-
return err
116-
}
107+
if err := commands.Init(&rpc.InitRequest{Instance: req.Instance}, nil); err != nil {
108+
return err
117109
}
118110

119111
return nil
120112
}
121113

122-
func installLibrary(lm *librariesmanager.LibrariesManager, libRelease *librariesindex.Release, installLocation libraries.LibraryLocation, taskCB rpc.TaskProgressCB) error {
114+
func installLibrary(lm *librariesmanager.LibrariesManager, libRelease *librariesindex.Release, installTask *librariesmanager.LibraryInstallPlan, taskCB rpc.TaskProgressCB) error {
123115
taskCB(&rpc.TaskProgress{Name: tr("Installing %s", libRelease)})
124116
logrus.WithField("library", libRelease).Info("Installing library")
125-
libPath, libReplaced, err := lm.InstallPrerequisiteCheck(libRelease.Library.Name, libRelease.Version, installLocation)
126-
if errors.Is(err, librariesmanager.ErrAlreadyInstalled) {
127-
taskCB(&rpc.TaskProgress{Message: tr("Already installed %s", libRelease), Completed: true})
128-
return err
129-
}
130117

131-
if err != nil {
132-
return &arduino.FailedInstallError{Message: tr("Checking lib install prerequisites"), Cause: err}
133-
}
134-
135-
if libReplaced != nil {
118+
if libReplaced := installTask.ReplacedLib; libReplaced != nil {
136119
taskCB(&rpc.TaskProgress{Message: tr("Replacing %[1]s with %[2]s", libReplaced, libRelease)})
137-
}
138-
139-
if err := lm.Install(libRelease, libPath); err != nil {
140-
return &arduino.FailedLibraryInstallError{Cause: err}
141-
}
142-
if libReplaced != nil && !libReplaced.InstallDir.EquivalentTo(libPath) {
143120
if err := lm.Uninstall(libReplaced); err != nil {
144-
return fmt.Errorf("%s: %s", tr("could not remove old library"), err)
121+
return &arduino.FailedLibraryInstallError{
122+
Cause: fmt.Errorf("%s: %s", tr("could not remove old library"), err)}
145123
}
146124
}
125+
if err := lm.Install(libRelease, installTask.TargetPath); err != nil {
126+
return &arduino.FailedLibraryInstallError{Cause: err}
127+
}
128+
147129
taskCB(&rpc.TaskProgress{Message: tr("Installed %s", libRelease), Completed: true})
148130
return nil
149131
}

0 commit comments

Comments
 (0)