Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9c5ec42

Browse files
vinay-lankavinay-lanka
vinay-lanka
authored andcommittedNov 4, 2020
Added tests for lib install with flags
1 parent 1c5e205 commit 9c5ec42

File tree

11 files changed

+366
-292
lines changed

11 files changed

+366
-292
lines changed
 

‎arduino/libraries/librariesmanager/install.go

Lines changed: 14 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,17 @@
1616
package librariesmanager
1717

1818
import (
19-
"archive/zip"
19+
"context"
2020
"errors"
2121
"fmt"
22-
"io"
2322
"os"
24-
"path/filepath"
2523
"strings"
2624

2725
"github.com/arduino/arduino-cli/arduino/libraries"
2826
"github.com/arduino/arduino-cli/arduino/libraries/librariesindex"
2927
"github.com/arduino/arduino-cli/arduino/utils"
3028
paths "github.com/arduino/go-paths-helper"
29+
"github.com/codeclysm/extract/v3"
3130
"gopkg.in/src-d/go-git.v4"
3231
)
3332

@@ -93,94 +92,37 @@ func (lm *LibrariesManager) Uninstall(lib *libraries.Library) error {
9392
}
9493

9594
//InstallZipLib installs a Zip library on the specified path.
96-
func (lm *LibrariesManager) InstallZipLib(libPath string) error {
95+
func (lm *LibrariesManager) InstallZipLib(ctx context.Context, archivePath string) error {
9796
libsDir := lm.getUserLibrariesDir()
9897
if libsDir == nil {
9998
return fmt.Errorf("User directory not set")
10099
}
101-
err := Unzip(libPath, libsDir.String())
102-
if err != nil {
103-
return err
104-
}
105-
return nil
106-
}
107-
108-
//Unzip takes the ZipLibPath and Extracts it to LibsDir
109-
func Unzip(src string, dest string) error {
110-
111-
var filenames []string
112100

113-
r, err := zip.OpenReader(src)
101+
file, err := os.Open(archivePath)
114102
if err != nil {
115103
return err
116104
}
117-
defer r.Close()
118-
119-
for _, f := range r.File {
120-
121-
// Store filename/path for returning and using later on
122-
fpath := filepath.Join(dest, f.Name)
123-
124-
// Check for ZipSlip. More Info: http://bit.ly/2MsjAWE
125-
if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
126-
return fmt.Errorf("%s: illegal file path", fpath)
127-
}
128-
129-
filenames = append(filenames, fpath)
130-
131-
if f.FileInfo().IsDir() {
132-
// Make Folder
133-
os.MkdirAll(fpath, os.ModePerm)
134-
continue
135-
}
105+
defer file.Close()
136106

137-
// Make File
138-
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
139-
return err
140-
}
141-
142-
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
143-
if err != nil {
144-
return err
145-
}
146-
147-
rc, err := f.Open()
148-
if err != nil {
149-
return err
150-
}
151-
152-
_, err = io.Copy(outFile, rc)
153-
154-
// Close the file without defer to close before next iteration of loop
155-
outFile.Close()
156-
rc.Close()
157-
158-
if err != nil {
159-
return err
160-
}
107+
if err := extract.Archive(ctx, file, libsDir.String(), nil); err != nil {
108+
return fmt.Errorf("extracting archive: %s", err)
161109
}
162110
return nil
163111
}
164112

165113
//InstallGitLib installs a library hosted on a git repository on the specified path.
166-
func (lm *LibrariesManager) InstallGitLib(Name string, gitURL string) error {
114+
func (lm *LibrariesManager) InstallGitLib(url string) error {
167115
libsDir := lm.getUserLibrariesDir()
168116
if libsDir == nil {
169117
return fmt.Errorf("User directory not set")
170118
}
171-
err := Fetch(Name, gitURL, libsDir.String())
172-
if err != nil {
173-
return err
174-
}
175-
return nil
176-
}
119+
i := strings.LastIndex(url, "/")
120+
folder := strings.TrimRight(url[i+1:], ".git")
121+
path := libsDir.Join(folder)
177122

178-
//Fetch Clones the repository to LibsDir
179-
func Fetch(name string, url string, dest string) error {
180-
directory := dest + "/" + name
181-
_, err := git.PlainClone(directory, false, &git.CloneOptions{
182-
URL: url,
183-
RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
123+
_, err := git.PlainClone(path.String(), false, &git.CloneOptions{
124+
URL: url,
125+
Progress: os.Stdout,
184126
})
185127
if err != nil {
186128
return err

‎cli/lib/install.go

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,38 +40,37 @@ func initInstallCommand() *cobra.Command {
4040
Run: runInstallCommand,
4141
}
4242
installCommand.Flags().BoolVar(&installFlags.noDeps, "no-deps", false, "Do not install dependencies.")
43-
installCommand.Flags().StringVarP(&installFlags.gitURL, "git-url", "g", "", "Enter git url for libraries hosted on repositories")
44-
installCommand.Flags().StringVarP(&installFlags.zipPath, "zip-path", "z", "", "Enter a path to zip file")
43+
installCommand.Flags().BoolVar(&installFlags.gitURL, "git-url", false, "Enter git url for libraries hosted on repositories")
44+
installCommand.Flags().BoolVar(&installFlags.zipPath, "zip-path", false, "Enter a path to zip file")
4545
return installCommand
4646
}
4747

4848
var installFlags struct {
4949
noDeps bool
50-
gitURL string
51-
zipPath string
50+
gitURL bool
51+
zipPath bool
5252
}
5353

5454
func runInstallCommand(cmd *cobra.Command, args []string) {
5555
instance := instance.CreateInstanceIgnorePlatformIndexErrors()
56-
if installFlags.zipPath != "" {
57-
ZiplibraryInstallReq := &rpc.ZipLibraryInstallReq{
56+
if installFlags.zipPath {
57+
ziplibraryInstallReq := &rpc.ZipLibraryInstallReq{
5858
Instance: instance,
59-
Path: installFlags.zipPath,
59+
Path: args[0],
6060
}
61-
_, err := lib.ZipLibraryInstall(context.Background(), ZiplibraryInstallReq)
61+
err := lib.ZipLibraryInstall(context.Background(), ziplibraryInstallReq, output.TaskProgress())
6262
if err != nil {
63-
feedback.Errorf("Error installing Zip Library %v", err)
63+
feedback.Errorf("Error installing Zip Library: %v", err)
6464
os.Exit(errorcodes.ErrGeneric)
6565
}
66-
} else if installFlags.gitURL != "" {
67-
GitlibraryInstallReq := &rpc.GitLibraryInstallReq{
66+
} else if installFlags.gitURL {
67+
gitlibraryInstallReq := &rpc.GitLibraryInstallReq{
6868
Instance: instance,
69-
Name: args[0],
70-
Url: installFlags.gitURL,
69+
Url: args[0],
7170
}
72-
_, err := lib.GitLibraryInstall(context.Background(), GitlibraryInstallReq)
71+
err := lib.GitLibraryInstall(context.Background(), gitlibraryInstallReq, output.TaskProgress())
7372
if err != nil {
74-
feedback.Errorf("Error installing Git Library %v", err)
73+
feedback.Errorf("Error installing Git Library: %v", err)
7574
os.Exit(errorcodes.ErrGeneric)
7675
}
7776
} else {

‎commands/daemon/daemon.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,11 +358,25 @@ func (s *ArduinoCoreServerImpl) ArchiveSketch(ctx context.Context, req *rpc.Arch
358358
}
359359

360360
//ZipLibraryInstall FIXMEDOC
361-
func (s *ArduinoCoreServerImpl) ZipLibraryInstall(ctx context.Context, req *rpc.ZipLibraryInstallReq) (*rpc.ZipLibraryInstallResp, error) {
362-
return lib.ZipLibraryInstall(ctx, req)
361+
func (s *ArduinoCoreServerImpl) ZipLibraryInstall(req *rpc.ZipLibraryInstallReq, stream rpc.ArduinoCore_ZipLibraryInstallServer) error {
362+
err := lib.ZipLibraryInstall(
363+
stream.Context(), req,
364+
func(p *rpc.TaskProgress) { stream.Send(&rpc.ZipLibraryInstallResp{TaskProgress: p}) },
365+
)
366+
if err != nil {
367+
return err
368+
}
369+
return stream.Send(&rpc.ZipLibraryInstallResp{})
363370
}
364371

365372
//GitLibraryInstall FIXMEDOC
366-
func (s *ArduinoCoreServerImpl) GitLibraryInstall(ctx context.Context, req *rpc.GitLibraryInstallReq) (*rpc.GitLibraryInstallResp, error) {
367-
return lib.GitLibraryInstall(ctx, req)
373+
func (s *ArduinoCoreServerImpl) GitLibraryInstall(req *rpc.GitLibraryInstallReq, stream rpc.ArduinoCore_GitLibraryInstallServer) error {
374+
err := lib.GitLibraryInstall(
375+
stream.Context(), req,
376+
func(p *rpc.TaskProgress) { stream.Send(&rpc.GitLibraryInstallResp{TaskProgress: p}) },
377+
)
378+
if err != nil {
379+
return err
380+
}
381+
return stream.Send(&rpc.GitLibraryInstallResp{})
368382
}

‎commands/lib/install.go

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -77,42 +77,23 @@ func installLibrary(lm *librariesmanager.LibrariesManager, libRelease *libraries
7777
}
7878

7979
//ZipLibraryInstall FIXMEDOC
80-
func ZipLibraryInstall(ctx context.Context, req *rpc.ZipLibraryInstallReq) (*rpc.ZipLibraryInstallResp, error) {
81-
res := &rpc.ZipLibraryInstallResp{}
80+
func ZipLibraryInstall(ctx context.Context, req *rpc.ZipLibraryInstallReq, taskCB commands.TaskProgressCB) error {
8281
lm := commands.GetLibraryManager(req.GetInstance().GetId())
83-
Path := req.GetPath()
84-
if err := installZipLibrary(lm, Path); err != nil {
85-
res.Status = "Error installing Zip Library"
86-
return res, err
87-
}
88-
res.Status = "Success! Installed Zip Library"
89-
return res, nil
90-
}
91-
92-
func installZipLibrary(lm *librariesmanager.LibrariesManager, libPath string) error {
93-
if err := lm.InstallZipLib(libPath); err != nil {
82+
archivePath := req.GetPath()
83+
if err := lm.InstallZipLib(ctx, archivePath); err != nil {
9484
return err
9585
}
86+
taskCB(&rpc.TaskProgress{Message: "Installed Archived Library", Completed: true})
9687
return nil
9788
}
9889

9990
//GitLibraryInstall FIXMEDOC
100-
func GitLibraryInstall(ctx context.Context, req *rpc.GitLibraryInstallReq) (*rpc.GitLibraryInstallResp, error) {
101-
res := &rpc.GitLibraryInstallResp{}
91+
func GitLibraryInstall(ctx context.Context, req *rpc.GitLibraryInstallReq, taskCB commands.TaskProgressCB) error {
10292
lm := commands.GetLibraryManager(req.GetInstance().GetId())
103-
URL := req.GetUrl()
104-
Name := req.GetName()
105-
if err := installGitLibrary(lm, Name, URL); err != nil {
106-
res.Status = "Error installing Git Library"
107-
return res, err
108-
}
109-
res.Status = "Success! Installed Git Library"
110-
return res, nil
111-
}
112-
113-
func installGitLibrary(lm *librariesmanager.LibrariesManager, Name string, gitURL string) error {
114-
if err := lm.InstallGitLib(Name, gitURL); err != nil {
93+
url := req.GetUrl()
94+
if err := lm.InstallGitLib(url); err != nil {
11595
return err
11696
}
97+
taskCB(&rpc.TaskProgress{Message: "Installed Library from Git URL", Completed: true})
11798
return nil
11899
}

‎go.mod

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,10 @@ require (
2121
github.com/h2non/filetype v1.0.8 // indirect
2222
github.com/imjasonmiller/godice v0.1.2
2323
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 // indirect
24-
github.com/leonelquinteros/gotext v1.4.0
25-
github.com/marcinbor85/gohex v0.0.0-20200531163658-baab2527a9a2
26-
github.com/juju/testing v0.0.0-20190429233213-dfc56b8c09fc // indirect
2724
github.com/kr/pretty v0.2.0 // indirect
2825
github.com/kr/text v0.2.0 // indirect
26+
github.com/leonelquinteros/gotext v1.4.0
27+
github.com/marcinbor85/gohex v0.0.0-20200531163658-baab2527a9a2
2928
github.com/mattn/go-colorable v0.1.2
3029
github.com/mattn/go-isatty v0.0.8
3130
github.com/mattn/go-runewidth v0.0.9 // indirect
@@ -48,17 +47,13 @@ require (
4847
go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18
4948
go.bug.st/serial v1.1.1
5049
go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45 // indirect
51-
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 // indirect
50+
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71
5251
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
53-
golang.org/x/sys v0.0.0-20200408040146-ea54a3c99b9b // indirect
5452
golang.org/x/text v0.3.2
5553
google.golang.org/grpc v1.27.0
5654
google.golang.org/protobuf v1.25.0
57-
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect
58-
gopkg.in/src-d/go-git.v4 v4.13.1
59-
gopkg.in/yaml.v2 v2.3.0
6055
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
6156
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect
6257
gopkg.in/src-d/go-git.v4 v4.13.1
63-
gopkg.in/yaml.v2 v2.2.4
58+
gopkg.in/yaml.v2 v2.3.0
6459
)

‎go.sum

Lines changed: 44 additions & 0 deletions
Large diffs are not rendered by default.

‎rpc/commands/commands.pb.go

Lines changed: 158 additions & 104 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎rpc/commands/commands.proto

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ service ArduinoCore {
123123
rpc LibraryInstall(LibraryInstallReq) returns (stream LibraryInstallResp);
124124

125125
// Install a library from a Zip File
126-
rpc ZipLibraryInstall(ZipLibraryInstallReq) returns (ZipLibraryInstallResp);
126+
rpc ZipLibraryInstall(ZipLibraryInstallReq) returns (stream ZipLibraryInstallResp);
127127

128128
// Download and install a library from a git url
129-
rpc GitLibraryInstall(GitLibraryInstallReq) returns (GitLibraryInstallResp);
129+
rpc GitLibraryInstall(GitLibraryInstallReq) returns (stream GitLibraryInstallResp);
130130

131131
// Uninstall an Arduino library.
132132
rpc LibraryUninstall(LibraryUninstallReq) returns (stream LibraryUninstallResp);

‎rpc/commands/lib.pb.go

Lines changed: 60 additions & 55 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎rpc/commands/lib.proto

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,20 +296,25 @@ enum LibraryLocation {
296296
}
297297

298298
message ZipLibraryInstallReq {
299+
// Arduino Core Service instance from the `Init` response.
299300
Instance instance = 1;
301+
//Path to the archived library
300302
string Path = 2;
301303
}
302304

303305
message ZipLibraryInstallResp {
304-
string status = 1;
306+
// Description of the current stage of the installation.
307+
TaskProgress task_progress = 1;
305308
}
306309

307310
message GitLibraryInstallReq {
311+
// Arduino Core Service instance from the `Init` response.
308312
Instance instance = 1;
309-
string name = 2;
310-
string url = 3;
313+
// URL to the repository containing the library
314+
string url = 2;
311315
}
312316

313317
message GitLibraryInstallResp {
314-
string status = 1;
318+
// Description of the current stage of the installation.
319+
TaskProgress task_progress = 1;
315320
}

‎test/test_lib.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# otherwise use the software for commercial activities involving the Arduino
1313
# software without disclosing the source code of your own applications. To purchase
1414
# a commercial license, send an email to license@arduino.cc.
15+
import os
1516
import simplejson as json
1617

1718

@@ -140,6 +141,21 @@ def test_list_with_fqbn(run_command):
140141
assert data[0]["library"]["compatible_with"]["arduino:avr:uno"]
141142

142143

144+
def test_lib_download(run_command, downloads_dir):
145+
146+
# Download a specific lib version
147+
assert run_command("lib download AudioZero@1.0.0")
148+
assert os.path.exists(os.path.join(downloads_dir, "libraries", "AudioZero-1.0.0.zip"))
149+
150+
# Wrong lib version
151+
result = run_command("lib download AudioZero@69.42.0")
152+
assert result.failed
153+
154+
# Wrong lib
155+
result = run_command("lib download AudioZ")
156+
assert result.failed
157+
158+
143159
def test_install(run_command):
144160
libs = ['"AzureIoTProtocol_MQTT"', '"CMMC MQTT Connector"', '"WiFiNINA"']
145161
# Should be safe to run install multiple times
@@ -152,6 +168,25 @@ def test_install(run_command):
152168
assert "Error resolving dependencies for MD_Parola@3.2.0: dependency 'MD_MAX72xx' is not available" in result.stderr
153169

154170

171+
def test_install_with_git_url(run_command):
172+
# Test git-url library install
173+
assert run_command("lib install --git-url https://github.com/arduino-libraries/WiFi101.git")
174+
175+
# Test failing-install as repository already exists
176+
result = run_command("lib install --git-url https://github.com/arduino-libraries/WiFi101.git")
177+
assert "Error installing Git Library: repository already exists" in result.stderr
178+
179+
180+
def test_install_with_zip_path(run_command, downloads_dir):
181+
# Download a specific lib version
182+
assert run_command("lib download AudioZero@1.0.0")
183+
assert os.path.exists(os.path.join(downloads_dir, "libraries", "AudioZero-1.0.0.zip"))
184+
185+
zip_path = os.path.join(downloads_dir, "libraries", "AudioZero-1.0.0.zip")
186+
# Test zip-path install
187+
assert run_command("lib install --zip-path {zip_path}".format(zip_path=zip_path))
188+
189+
155190
def test_update_index(run_command):
156191
result = run_command("lib update-index")
157192
assert result.ok

0 commit comments

Comments
 (0)
Please sign in to comment.