Skip to content

Commit bacc2ac

Browse files
authored
lib install --git-url and --zip-file must now be esplicitly enabled (#1075)
1 parent f7cdf72 commit bacc2ac

File tree

3 files changed

+139
-58
lines changed

3 files changed

+139
-58
lines changed

cli/lib/install.go

+60-48
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/arduino/arduino-cli/cli/instance"
2525
"github.com/arduino/arduino-cli/cli/output"
2626
"github.com/arduino/arduino-cli/commands/lib"
27+
"github.com/arduino/arduino-cli/configuration"
2728
rpc "github.com/arduino/arduino-cli/rpc/commands"
2829
"github.com/spf13/cobra"
2930
)
@@ -40,8 +41,10 @@ func initInstallCommand() *cobra.Command {
4041
Run: runInstallCommand,
4142
}
4243
installCommand.Flags().BoolVar(&installFlags.noDeps, "no-deps", false, "Do not install dependencies.")
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")
44+
if configuration.Settings.GetBool("library.enable_unsafe_install") {
45+
installCommand.Flags().BoolVar(&installFlags.gitURL, "git-url", false, "Enter git url for libraries hosted on repositories")
46+
installCommand.Flags().BoolVar(&installFlags.zipPath, "zip-path", false, "Enter a path to zip file")
47+
}
4548
return installCommand
4649
}
4750

@@ -53,6 +56,11 @@ var installFlags struct {
5356

5457
func runInstallCommand(cmd *cobra.Command, args []string) {
5558
instance := instance.CreateInstanceIgnorePlatformIndexErrors()
59+
60+
if installFlags.zipPath || installFlags.gitURL {
61+
feedback.Print("--git-url and --zip-path flags are dangerous, use it at your own risk.")
62+
}
63+
5664
if installFlags.zipPath {
5765
ziplibraryInstallReq := &rpc.ZipLibraryInstallReq{
5866
Instance: instance,
@@ -63,7 +71,10 @@ func runInstallCommand(cmd *cobra.Command, args []string) {
6371
feedback.Errorf("Error installing Zip Library: %v", err)
6472
os.Exit(errorcodes.ErrGeneric)
6573
}
66-
} else if installFlags.gitURL {
74+
return
75+
}
76+
77+
if installFlags.gitURL {
6778
gitlibraryInstallReq := &rpc.GitLibraryInstallReq{
6879
Instance: instance,
6980
Url: args[0],
@@ -73,58 +84,59 @@ func runInstallCommand(cmd *cobra.Command, args []string) {
7384
feedback.Errorf("Error installing Git Library: %v", err)
7485
os.Exit(errorcodes.ErrGeneric)
7586
}
76-
} else {
77-
libRefs, err := ParseLibraryReferenceArgsAndAdjustCase(instance, args)
78-
if err != nil {
79-
feedback.Errorf("Arguments error: %v", err)
80-
os.Exit(errorcodes.ErrBadArgument)
81-
}
87+
return
88+
}
8289

83-
toInstall := map[string]*rpc.LibraryDependencyStatus{}
84-
if installFlags.noDeps {
85-
for _, libRef := range libRefs {
86-
toInstall[libRef.Name] = &rpc.LibraryDependencyStatus{
87-
Name: libRef.Name,
88-
VersionRequired: libRef.Version,
89-
}
90-
}
91-
} else {
92-
for _, libRef := range libRefs {
93-
depsResp, err := lib.LibraryResolveDependencies(context.Background(), &rpc.LibraryResolveDependenciesReq{
94-
Instance: instance,
95-
Name: libRef.Name,
96-
Version: libRef.Version,
97-
})
98-
if err != nil {
99-
feedback.Errorf("Error resolving dependencies for %s: %s", libRef, err)
100-
os.Exit(errorcodes.ErrGeneric)
101-
}
102-
for _, dep := range depsResp.GetDependencies() {
103-
feedback.Printf("%s depends on %s@%s", libRef, dep.GetName(), dep.GetVersionRequired())
104-
if existingDep, has := toInstall[dep.GetName()]; has {
105-
if existingDep.GetVersionRequired() != dep.GetVersionRequired() {
106-
// TODO: make a better error
107-
feedback.Errorf("The library %s is required in two different versions: %s and %s",
108-
dep.GetName(), dep.GetVersionRequired(), existingDep.GetVersionRequired())
109-
os.Exit(errorcodes.ErrGeneric)
110-
}
111-
}
112-
toInstall[dep.GetName()] = dep
113-
}
90+
libRefs, err := ParseLibraryReferenceArgsAndAdjustCase(instance, args)
91+
if err != nil {
92+
feedback.Errorf("Arguments error: %v", err)
93+
os.Exit(errorcodes.ErrBadArgument)
94+
}
95+
96+
toInstall := map[string]*rpc.LibraryDependencyStatus{}
97+
if installFlags.noDeps {
98+
for _, libRef := range libRefs {
99+
toInstall[libRef.Name] = &rpc.LibraryDependencyStatus{
100+
Name: libRef.Name,
101+
VersionRequired: libRef.Version,
114102
}
115103
}
116-
117-
for _, library := range toInstall {
118-
libraryInstallReq := &rpc.LibraryInstallReq{
104+
} else {
105+
for _, libRef := range libRefs {
106+
depsResp, err := lib.LibraryResolveDependencies(context.Background(), &rpc.LibraryResolveDependenciesReq{
119107
Instance: instance,
120-
Name: library.Name,
121-
Version: library.VersionRequired,
122-
}
123-
err := lib.LibraryInstall(context.Background(), libraryInstallReq, output.ProgressBar(), output.TaskProgress())
108+
Name: libRef.Name,
109+
Version: libRef.Version,
110+
})
124111
if err != nil {
125-
feedback.Errorf("Error installing %s: %v", library, err)
112+
feedback.Errorf("Error resolving dependencies for %s: %s", libRef, err)
126113
os.Exit(errorcodes.ErrGeneric)
127114
}
115+
for _, dep := range depsResp.GetDependencies() {
116+
feedback.Printf("%s depends on %s@%s", libRef, dep.GetName(), dep.GetVersionRequired())
117+
if existingDep, has := toInstall[dep.GetName()]; has {
118+
if existingDep.GetVersionRequired() != dep.GetVersionRequired() {
119+
// TODO: make a better error
120+
feedback.Errorf("The library %s is required in two different versions: %s and %s",
121+
dep.GetName(), dep.GetVersionRequired(), existingDep.GetVersionRequired())
122+
os.Exit(errorcodes.ErrGeneric)
123+
}
124+
}
125+
toInstall[dep.GetName()] = dep
126+
}
127+
}
128+
}
129+
130+
for _, library := range toInstall {
131+
libraryInstallReq := &rpc.LibraryInstallReq{
132+
Instance: instance,
133+
Name: library.Name,
134+
Version: library.VersionRequired,
135+
}
136+
err := lib.LibraryInstall(context.Background(), libraryInstallReq, output.ProgressBar(), output.TaskProgress())
137+
if err != nil {
138+
feedback.Errorf("Error installing %s: %v", library, err)
139+
os.Exit(errorcodes.ErrGeneric)
128140
}
129141
}
130142
}

configuration/defaults.go

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ func SetDefaults(settings *viper.Viper) {
2828
settings.SetDefault("logging.level", "info")
2929
settings.SetDefault("logging.format", "text")
3030

31+
// Libraries
32+
settings.SetDefault("library.enable_unsafe_install", false)
33+
3134
// Boards Manager
3235
settings.SetDefault("board_manager.additional_urls", []string{})
3336

@@ -52,6 +55,7 @@ func SetDefaults(settings *viper.Viper) {
5255
settings.AutomaticEnv()
5356

5457
// Bind env aliases to keep backward compatibility
58+
settings.BindEnv("library.enable_unsafe_install", "ARDUINO_ENABLE_UNSAFE_LIBRARY_INSTALL")
5559
settings.BindEnv("directories.User", "ARDUINO_SKETCHBOOK_DIR")
5660
settings.BindEnv("directories.Downloads", "ARDUINO_DOWNLOADS_DIR")
5761
settings.BindEnv("directories.Data", "ARDUINO_DATA_DIR")

test/test_lib.py

+75-10
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
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 [email protected].
15-
import os
1615
import simplejson as json
16+
from pathlib import Path
1717

1818

1919
def test_list(run_command):
@@ -145,7 +145,7 @@ def test_lib_download(run_command, downloads_dir):
145145

146146
# Download a specific lib version
147147
assert run_command("lib download [email protected]")
148-
assert os.path.exists(os.path.join(downloads_dir, "libraries", "AudioZero-1.0.0.zip"))
148+
assert Path(downloads_dir, "libraries", "AudioZero-1.0.0.zip").exists()
149149

150150
# Wrong lib version
151151
result = run_command("lib download [email protected]")
@@ -168,23 +168,88 @@ def test_install(run_command):
168168
assert "Error resolving dependencies for [email protected]: dependency 'MD_MAX72xx' is not available" in result.stderr
169169

170170

171-
def test_install_with_git_url(run_command):
171+
def test_install_git_url_and_zip_path_flags_visibility(run_command, data_dir, downloads_dir):
172+
# Verifies installation fail because flags are not found
173+
git_url = "https://github.com/arduino-libraries/WiFi101.git"
174+
res = run_command(f"lib install --git-url {git_url}")
175+
assert res.failed
176+
assert "Error: unknown flag: --git-url" in res.stderr
177+
178+
assert run_command("lib download [email protected]")
179+
zip_path = Path(downloads_dir, "libraries", "AudioZero-1.0.0.zip")
180+
res = run_command(f"lib install --zip-path {zip_path}")
181+
assert res.failed
182+
assert "Error: unknown flag: --zip-path" in res.stderr
183+
184+
env = {
185+
"ARDUINO_DATA_DIR": data_dir,
186+
"ARDUINO_DOWNLOADS_DIR": downloads_dir,
187+
"ARDUINO_SKETCHBOOK_DIR": data_dir,
188+
"ARDUINO_ENABLE_UNSAFE_LIBRARY_INSTALL": "true",
189+
}
190+
# Verifies installation is successful when flags are enabled with env var
191+
res = run_command(f"lib install --git-url {git_url}", custom_env=env)
192+
assert res.ok
193+
assert "--git-url and --zip-path flags are dangerous, use it at your own risk." in res.stdout
194+
195+
res = run_command(f"lib install --zip-path {zip_path}", custom_env=env)
196+
assert res.ok
197+
assert "--git-url and --zip-path flags are dangerous, use it at your own risk." in res.stdout
198+
199+
# Uninstall libraries to install them again
200+
assert run_command("lib uninstall WiFi101 AudioZero")
201+
202+
# Verifies installation is successful when flags are enabled with settings file
203+
assert run_command("config init --dest-dir .", custom_env=env)
204+
205+
res = run_command(f"lib install --git-url {git_url}")
206+
assert res.ok
207+
assert "--git-url and --zip-path flags are dangerous, use it at your own risk." in res.stdout
208+
209+
res = run_command(f"lib install --zip-path {zip_path}")
210+
assert res.ok
211+
assert "--git-url and --zip-path flags are dangerous, use it at your own risk." in res.stdout
212+
213+
214+
def test_install_with_git_url(run_command, data_dir, downloads_dir):
215+
# Initialize configs to enable --git-url flag
216+
env = {
217+
"ARDUINO_DATA_DIR": data_dir,
218+
"ARDUINO_DOWNLOADS_DIR": downloads_dir,
219+
"ARDUINO_SKETCHBOOK_DIR": data_dir,
220+
"ARDUINO_ENABLE_UNSAFE_LIBRARY_INSTALL": "true",
221+
}
222+
assert run_command("config init --dest-dir .", custom_env=env)
223+
172224
# Test git-url library install
173-
assert run_command("lib install --git-url https://github.com/arduino-libraries/WiFi101.git")
225+
res = run_command("lib install --git-url https://github.com/arduino-libraries/WiFi101.git")
226+
assert res.ok
227+
assert "--git-url and --zip-path flags are dangerous, use it at your own risk." in res.stdout
174228

175229
# 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
230+
res = run_command("lib install --git-url https://github.com/arduino-libraries/WiFi101.git")
231+
assert "--git-url and --zip-path flags are dangerous, use it at your own risk." in res.stdout
232+
assert "Error installing Git Library: repository already exists" in res.stderr
178233

179234

180-
def test_install_with_zip_path(run_command, downloads_dir):
235+
def test_install_with_zip_path(run_command, data_dir, downloads_dir):
236+
# Initialize configs to enable --zip-path flag
237+
env = {
238+
"ARDUINO_DATA_DIR": data_dir,
239+
"ARDUINO_DOWNLOADS_DIR": downloads_dir,
240+
"ARDUINO_SKETCHBOOK_DIR": data_dir,
241+
"ARDUINO_ENABLE_UNSAFE_LIBRARY_INSTALL": "true",
242+
}
243+
assert run_command("config init --dest-dir .", custom_env=env)
244+
181245
# Download a specific lib version
182246
assert run_command("lib download [email protected]")
183-
assert os.path.exists(os.path.join(downloads_dir, "libraries", "AudioZero-1.0.0.zip"))
184247

185-
zip_path = os.path.join(downloads_dir, "libraries", "AudioZero-1.0.0.zip")
248+
zip_path = Path(downloads_dir, "libraries", "AudioZero-1.0.0.zip")
186249
# Test zip-path install
187-
assert run_command("lib install --zip-path {zip_path}".format(zip_path=zip_path))
250+
res = run_command(f"lib install --zip-path {zip_path}")
251+
assert res.ok
252+
assert "--git-url and --zip-path flags are dangerous, use it at your own risk." in res.stdout
188253

189254

190255
def test_update_index(run_command):

0 commit comments

Comments
 (0)