Skip to content

Commit e7db62f

Browse files
silvanocerzaper1234
andcommitted
Fix library verification when installing from git repo or zip file (#1466)
* Fix library verification when installing from git repo or zip file * Enhance code comments and unit tests Co-authored-by: per1234 <[email protected]> Co-authored-by: per1234 <[email protected]>
1 parent 59f748d commit e7db62f

File tree

7 files changed

+130
-47
lines changed

7 files changed

+130
-47
lines changed

Diff for: arduino/globals/globals.go

+7
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,11 @@ var (
4949
".cpp": empty,
5050
".S": empty,
5151
}
52+
53+
// HeaderFilesValidExtensions lists valid extensions for header files
54+
HeaderFilesValidExtensions = map[string]struct{}{
55+
".h": empty,
56+
".hpp": empty,
57+
".hh": empty,
58+
}
5259
)

Diff for: arduino/libraries/libraries.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"fmt"
2020

2121
"github.com/arduino/arduino-cli/arduino/cores"
22+
"github.com/arduino/arduino-cli/arduino/globals"
2223
"github.com/arduino/arduino-cli/i18n"
2324
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
2425
paths "github.com/arduino/go-paths-helper"
@@ -233,7 +234,11 @@ func (library *Library) SourceHeaders() ([]string, error) {
233234
if err != nil {
234235
return nil, fmt.Errorf(tr("reading lib src dir: %s"), err)
235236
}
236-
cppHeaders.FilterSuffix(".h", ".hpp", ".hh")
237+
headerExtensions := []string{}
238+
for k := range globals.HeaderFilesValidExtensions {
239+
headerExtensions = append(headerExtensions, k)
240+
}
241+
cppHeaders.FilterSuffix(headerExtensions...)
237242
res := []string{}
238243
for _, cppHeader := range cppHeaders {
239244
res = append(res, cppHeader.Base())

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

+41-15
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"os"
2424
"strings"
2525

26+
"github.com/arduino/arduino-cli/arduino/globals"
2627
"github.com/arduino/arduino-cli/arduino/libraries"
2728
"github.com/arduino/arduino-cli/arduino/libraries/librariesindex"
2829
"github.com/arduino/arduino-cli/arduino/utils"
@@ -134,7 +135,7 @@ func (lm *LibrariesManager) InstallZipLib(ctx context.Context, archivePath strin
134135
extractionPath := paths[0]
135136
libraryName := extractionPath.Base()
136137

137-
if err := validateLibrary(libraryName, extractionPath); err != nil {
138+
if err := validateLibrary(extractionPath); err != nil {
138139
return err
139140
}
140141

@@ -224,7 +225,7 @@ func (lm *LibrariesManager) InstallGitLib(gitURL string, overwrite bool) error {
224225
return err
225226
}
226227

227-
if err := validateLibrary(libraryName, installPath); err != nil {
228+
if err := validateLibrary(installPath); err != nil {
228229
// Clean up installation directory since this is not a valid library
229230
installPath.RemoveAll()
230231
return err
@@ -254,22 +255,47 @@ func parseGitURL(gitURL string) (string, error) {
254255
return res, nil
255256
}
256257

257-
// validateLibrary verifies the dir contains a valid library, meaning it has both
258-
// an header <name>.h, either in src or root folder, and a library.properties file
259-
func validateLibrary(name string, dir *paths.Path) error {
260-
// Verify library contains library header.
261-
// Checks also root folder for legacy reasons.
262-
// For more info see:
258+
// validateLibrary verifies the dir contains a valid library, meaning it has either
259+
// library.properties file and an header in src/ or an header in its root folder.
260+
// Returns nil if dir contains a valid library, error on all other cases.
261+
func validateLibrary(dir *paths.Path) error {
262+
if dir.NotExist() {
263+
return fmt.Errorf(tr("directory doesn't exist: %s", dir))
264+
}
265+
266+
searchHeaderFile := func(d *paths.Path) (bool, error) {
267+
if d.NotExist() {
268+
// A directory that doesn't exist can't obviously contain any header file
269+
return false, nil
270+
}
271+
dirContent, err := d.ReadDir()
272+
if err != nil {
273+
return false, fmt.Errorf(tr("reading directory %s content: %w", dir, err))
274+
}
275+
dirContent.FilterOutDirs()
276+
headerExtensions := []string{}
277+
for k := range globals.HeaderFilesValidExtensions {
278+
headerExtensions = append(headerExtensions, k)
279+
}
280+
dirContent.FilterSuffix(headerExtensions...)
281+
return len(dirContent) > 0, nil
282+
}
283+
284+
// Recursive library layout
263285
// https://arduino.github.io/arduino-cli/latest/library-specification/#source-code
264-
libraryHeader := name + ".h"
265-
if !dir.Join("src", libraryHeader).Exist() && !dir.Join(libraryHeader).Exist() {
266-
return fmt.Errorf(tr(`library is not valid: missing header file "%s"`), libraryHeader)
286+
if headerFound, err := searchHeaderFile(dir.Join("src")); err != nil {
287+
return err
288+
} else if dir.Join("library.properties").Exist() && headerFound {
289+
return nil
267290
}
268291

269-
// Verifies library contains library.properties
270-
if !dir.Join("library.properties").Exist() {
271-
return fmt.Errorf(tr(`library is not valid: missing file "library.properties"`))
292+
// Flat library layout
293+
// https://arduino.github.io/arduino-cli/latest/library-specification/#source-code
294+
if headerFound, err := searchHeaderFile(dir); err != nil {
295+
return err
296+
} else if headerFound {
297+
return nil
272298
}
273299

274-
return nil
300+
return fmt.Errorf(tr("library not valid"))
275301
}

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

+41
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package librariesmanager
1818
import (
1919
"testing"
2020

21+
"github.com/arduino/go-paths-helper"
2122
"github.com/stretchr/testify/require"
2223
)
2324

@@ -62,3 +63,43 @@ func TestParseGitURL(t *testing.T) {
6263
require.Equal(t, "arduino-lib", libraryName)
6364
require.NoError(t, err)
6465
}
66+
67+
func TestValidateLibrary(t *testing.T) {
68+
tmpDir := paths.New(t.TempDir())
69+
70+
nonExistingDirLib := tmpDir.Join("nonExistingDirLib")
71+
err := validateLibrary(nonExistingDirLib)
72+
require.Errorf(t, err, "directory doesn't exist: %s", nonExistingDirLib)
73+
74+
emptyLib := tmpDir.Join("emptyLib")
75+
emptyLib.Mkdir()
76+
err = validateLibrary(emptyLib)
77+
require.Errorf(t, err, "library not valid")
78+
79+
onlyPropertiesLib := tmpDir.Join("onlyPropertiesLib")
80+
onlyPropertiesLib.Mkdir()
81+
onlyPropertiesLib.Join("library.properties").WriteFile([]byte{})
82+
err = validateLibrary(onlyPropertiesLib)
83+
require.Errorf(t, err, "library not valid")
84+
85+
missingPropertiesLib := tmpDir.Join("missingPropertiesLib")
86+
missingPropertiesLibSourceDir := missingPropertiesLib.Join("src")
87+
missingPropertiesLibSourceDir.MkdirAll()
88+
missingPropertiesLibSourceDir.Join("some_file.hpp").WriteFile([]byte{})
89+
err = validateLibrary(missingPropertiesLib)
90+
require.Errorf(t, err, "library not valid")
91+
92+
validLib := tmpDir.Join("valiLib")
93+
validLibSourceDir := validLib.Join("src")
94+
validLibSourceDir.MkdirAll()
95+
validLibSourceDir.Join("some_file.hpp").WriteFile([]byte{})
96+
validLib.Join("library.properties").WriteFile([]byte{})
97+
err = validateLibrary(validLib)
98+
require.NoError(t, err)
99+
100+
validLegacyLib := tmpDir.Join("validLegacyLib")
101+
validLegacyLib.Mkdir()
102+
validLegacyLib.Join("some_file.hpp").WriteFile([]byte{})
103+
err = validateLibrary(validLib)
104+
require.NoError(t, err)
105+
}

Diff for: i18n/data/en.po

+27-23
Original file line numberDiff line numberDiff line change
@@ -2268,10 +2268,10 @@ msgstr "Use %s for more information about a command."
22682268
msgid "Use the specified programmer to upload."
22692269
msgstr "Use the specified programmer to upload."
22702270

2271-
#: arduino/libraries/librariesmanager/install.go:62
2272-
#: arduino/libraries/librariesmanager/install.go:78
2273-
#: arduino/libraries/librariesmanager/install.go:100
2274-
#: arduino/libraries/librariesmanager/install.go:184
2271+
#: arduino/libraries/librariesmanager/install.go:63
2272+
#: arduino/libraries/librariesmanager/install.go:79
2273+
#: arduino/libraries/librariesmanager/install.go:101
2274+
#: arduino/libraries/librariesmanager/install.go:185
22752275
msgid "User directory not set"
22762276
msgstr "User directory not set"
22772277

@@ -2397,7 +2397,7 @@ msgstr "[DEPRECATED] %s"
23972397
msgid "archive hash differs from hash in index"
23982398
msgstr "archive hash differs from hash in index"
23992399

2400-
#: arduino/libraries/librariesmanager/install.go:131
2400+
#: arduino/libraries/librariesmanager/install.go:132
24012401
msgid "archive is not valid: multiple files found in zip file top level"
24022402
msgstr "archive is not valid: multiple files found in zip file top level"
24032403

@@ -2547,10 +2547,14 @@ msgstr "dependency '%s' is not available"
25472547
msgid "destination already exists"
25482548
msgstr "destination already exists"
25492549

2550-
#: arduino/libraries/librariesmanager/install.go:69
2550+
#: arduino/libraries/librariesmanager/install.go:70
25512551
msgid "destination dir %s already exists, cannot install"
25522552
msgstr "destination dir %s already exists, cannot install"
25532553

2554+
#: arduino/libraries/librariesmanager/install.go:263
2555+
msgid "directory doesn't exist: %s"
2556+
msgstr "directory doesn't exist: %s"
2557+
25542558
#: arduino/discovery/discoverymanager/discoverymanager.go:112
25552559
msgid "discovery %[1]s process not started: %[2]w"
25562560
msgstr "discovery %[1]s process not started: %[2]w"
@@ -2615,7 +2619,7 @@ msgstr "error: %s and %s flags cannot be used together"
26152619
msgid "extracting archive: %s"
26162620
msgstr "extracting archive: %s"
26172621

2618-
#: arduino/libraries/librariesmanager/install.go:119
2622+
#: arduino/libraries/librariesmanager/install.go:120
26192623
msgid "extracting archive: %w"
26202624
msgstr "extracting archive: %w"
26212625

@@ -2714,7 +2718,7 @@ msgstr "getting tool dependencies for platform %[1]s: %[2]s"
27142718
msgid "importing sketch metadata: %s"
27152719
msgstr "importing sketch metadata: %s"
27162720

2717-
#: arduino/libraries/librariesmanager/install.go:86
2721+
#: arduino/libraries/librariesmanager/install.go:87
27182722
msgid "install directory not set"
27192723
msgstr "install directory not set"
27202724

@@ -2775,7 +2779,7 @@ msgstr "invalid empty library version: %s"
27752779
msgid "invalid empty option found"
27762780
msgstr "invalid empty option found"
27772781

2778-
#: arduino/libraries/librariesmanager/install.go:252
2782+
#: arduino/libraries/librariesmanager/install.go:253
27792783
msgid "invalid git url"
27802784
msgstr "invalid git url"
27812785

@@ -2839,22 +2843,18 @@ msgstr "key not found in settings"
28392843
msgid "keywords"
28402844
msgstr "keywords"
28412845

2842-
#: arduino/libraries/librariesmanager/install.go:157
2843-
#: arduino/libraries/librariesmanager/install.go:200
2846+
#: arduino/libraries/librariesmanager/install.go:158
2847+
#: arduino/libraries/librariesmanager/install.go:201
28442848
msgid "library %s already installed"
28452849
msgstr "library %s already installed"
28462850

2847-
#: arduino/libraries/librariesmanager/install.go:38
2851+
#: arduino/libraries/librariesmanager/install.go:39
28482852
msgid "library already installed"
28492853
msgstr "library already installed"
28502854

2851-
#: arduino/libraries/librariesmanager/install.go:271
2852-
msgid "library is not valid: missing file \"library.properties\""
2853-
msgstr "library is not valid: missing file \"library.properties\""
2854-
2855-
#: arduino/libraries/librariesmanager/install.go:266
2856-
msgid "library is not valid: missing header file \"%s\""
2857-
msgstr "library is not valid: missing header file \"%s\""
2855+
#: arduino/libraries/librariesmanager/install.go:300
2856+
msgid "library not valid"
2857+
msgstr "library not valid"
28582858

28592859
#: arduino/libraries/librariesmanager/librariesmanager.go:226
28602860
msgid "library path does not exist: %s"
@@ -2933,7 +2933,7 @@ msgstr "missing platform %[1]s:%[2]s referenced by board %[3]s"
29332933
msgid "missing platform release %[1]s:%[2]s referenced by board %[3]s"
29342934
msgstr "missing platform release %[1]s:%[2]s referenced by board %[3]s"
29352935

2936-
#: arduino/libraries/librariesmanager/install.go:174
2936+
#: arduino/libraries/librariesmanager/install.go:175
29372937
#: arduino/resources/install.go:94
29382938
msgid "moving extracted archive to destination dir: %s"
29392939
msgstr "moving extracted archive to destination dir: %s"
@@ -3091,6 +3091,10 @@ msgstr "reading dir %[1]s: %[2]s"
30913091
msgid "reading directory %[1]s: %[2]s"
30923092
msgstr "reading directory %[1]s: %[2]s"
30933093

3094+
#: arduino/libraries/librariesmanager/install.go:273
3095+
msgid "reading directory %s content: %w"
3096+
msgstr "reading directory %s content: %w"
3097+
30943098
#: arduino/builder/sketch.go:76
30953099
msgid "reading file %[1]s: %[2]s"
30963100
msgstr "reading file %[1]s: %[2]s"
@@ -3107,11 +3111,11 @@ msgstr "reading inventory file: %w"
31073111
msgid "reading lib headers: %s"
31083112
msgstr "reading lib headers: %s"
31093113

3110-
#: arduino/libraries/libraries.go:234
3114+
#: arduino/libraries/libraries.go:235
31113115
msgid "reading lib src dir: %s"
31123116
msgstr "reading lib src dir: %s"
31133117

3114-
#: arduino/libraries/libraries.go:114
3118+
#: arduino/libraries/libraries.go:115
31153119
msgid "reading library headers: %w"
31163120
msgstr "reading library headers: %w"
31173121

@@ -3148,7 +3152,7 @@ msgstr "release not found"
31483152
msgid "removing corrupted archive file: %s"
31493153
msgstr "removing corrupted archive file: %s"
31503154

3151-
#: arduino/libraries/librariesmanager/install.go:89
3155+
#: arduino/libraries/librariesmanager/install.go:90
31523156
msgid "removing lib directory: %s"
31533157
msgstr "removing lib directory: %s"
31543158

Diff for: i18n/rice-box.go

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: test/test_lib.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ def test_install_zip_invalid_library(run_command, data_dir, downloads_dir):
925925
# Test zip-path install
926926
res = run_command(f"lib install --zip-path {zip_path}")
927927
assert res.failed
928-
assert 'library is not valid: missing header file "lib-without-header.h"' in res.stderr
928+
assert "library not valid" in res.stderr
929929

930930
lib_install_dir = Path(data_dir, "libraries", "lib-without-properties")
931931
# Verifies library is not already installed
@@ -935,7 +935,7 @@ def test_install_zip_invalid_library(run_command, data_dir, downloads_dir):
935935
# Test zip-path install
936936
res = run_command(f"lib install --zip-path {zip_path}")
937937
assert res.failed
938-
assert 'library is not valid: missing file "library.properties"' in res.stderr
938+
assert "library not valid" in res.stderr
939939

940940

941941
def test_install_git_invalid_library(run_command, data_dir, downloads_dir):
@@ -962,7 +962,7 @@ def test_install_git_invalid_library(run_command, data_dir, downloads_dir):
962962

963963
res = run_command(f"lib install --git-url {repo_dir}", custom_env=env)
964964
assert res.failed
965-
assert 'library is not valid: missing header file "lib-without-header.h"' in res.stderr
965+
assert "library not valid" in res.stderr
966966
assert not lib_install_dir.exists()
967967

968968
# Create another fake library repository
@@ -980,5 +980,5 @@ def test_install_git_invalid_library(run_command, data_dir, downloads_dir):
980980

981981
res = run_command(f"lib install --git-url {repo_dir}", custom_env=env)
982982
assert res.failed
983-
assert 'library is not valid: missing file "library.properties"' in res.stderr
983+
assert "library not valid" in res.stderr
984984
assert not lib_install_dir.exists()

0 commit comments

Comments
 (0)