diff --git a/arduino/libraries/libraries_test.go b/arduino/libraries/libraries_test.go index 68aef73ddf9..35c2a40ddfa 100644 --- a/arduino/libraries/libraries_test.go +++ b/arduino/libraries/libraries_test.go @@ -73,4 +73,15 @@ func TestLibrariesLoader(t *testing.T) { require.Equal(t, "LibWithNonUTF8Properties", lib.Name) require.Equal(t, "àrduìnò", lib.Author) } + { + lib, err := Load(paths.New("testdata", "EmptyLib"), User) + require.Error(t, err) + require.Nil(t, lib) + } + { + lib, err := Load(paths.New("testdata", "LegacyLib"), User) + require.NoError(t, err) + require.Equal(t, "LegacyLib", lib.Name) + require.True(t, lib.IsLegacy) + } } diff --git a/arduino/libraries/loader.go b/arduino/libraries/loader.go index 30c1822bfaa..ec3d1dc164a 100644 --- a/arduino/libraries/loader.go +++ b/arduino/libraries/loader.go @@ -19,6 +19,7 @@ import ( "fmt" "strings" + "github.com/arduino/arduino-cli/arduino/globals" "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/go-paths-helper" properties "github.com/arduino/go-properties-orderedmap" @@ -126,6 +127,11 @@ func makeNewLibrary(libraryDir *paths.Path, location LibraryLocation) (*Library, } func makeLegacyLibrary(path *paths.Path, location LibraryLocation) (*Library, error) { + if foundHeader, err := containsHeaderFile(path); err != nil { + return nil, err + } else if !foundHeader { + return nil, errors.Errorf(tr("invalid library: no header files found")) + } library := &Library{ InstallDir: path.Canonical(), Location: location, @@ -186,3 +192,19 @@ func addExamplesToPathList(examplesPath *paths.Path, list *paths.PathList) error } return nil } + +// containsHeaderFile returns true if the directory contains a ".h" file. +// Returns false otherwise +func containsHeaderFile(d *paths.Path) (bool, error) { + dirContent, err := d.ReadDir() + if err != nil { + return false, fmt.Errorf(tr("reading directory %[1]s content: %[2]w", d, err)) + } + dirContent.FilterOutDirs() + headerExtensions := []string{} + for k := range globals.HeaderFilesValidExtensions { + headerExtensions = append(headerExtensions, k) + } + dirContent.FilterSuffix(headerExtensions...) + return len(dirContent) > 0, nil +} diff --git a/arduino/libraries/testdata/LegacyLib/LegacyLib.h b/arduino/libraries/testdata/LegacyLib/LegacyLib.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/docs/library-specification.md b/docs/library-specification.md index 132cf2c3f35..a5fa721e57d 100644 --- a/docs/library-specification.md +++ b/docs/library-specification.md @@ -419,6 +419,6 @@ allowing the compilation to fail in a difficult to understand way): ## Old library format (pre-1.5) In order to support old libraries (from Arduino IDE 1.0.x), Arduino IDE and Arduino CLI will also compile libraries -missing a library.properties metadata file. As a result, these libraries should behave as they did in Arduino IDE 1.0.x, -although they will be available for all boards, including non-AVR ones (which wouldn’t have been present in Arduino IDE -1.0.x). +missing a library.properties metadata file (the header file is still required). As a result, these libraries should +behave as they did in Arduino IDE 1.0.x, although they will be available for all boards, including non-AVR ones (which +wouldn’t have been present in Arduino IDE 1.0.x). diff --git a/internal/integrationtest/lib/lib_test.go b/internal/integrationtest/lib/lib_test.go index 469002fbe42..b4b7f34c0f7 100644 --- a/internal/integrationtest/lib/lib_test.go +++ b/internal/integrationtest/lib/lib_test.go @@ -1587,3 +1587,40 @@ func TestLibBundlesWhenLibWithTheSameNameIsInstalledGlobally(t *testing.T) { requirejson.Parse(t, stdout).Query(`.[].library.examples[1]`).MustContain(`"OTALeds"`) } } + +func TestLibListDoesNotIncludeEmptyLibraries(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + _, _, err := cli.Run("lib", "update-index") + require.NoError(t, err) + + // Create a library that does not have neither a library.properties nor a ".h" file + emptyLib := cli.SketchbookDir().Join("libraries", "empty") + require.NoError(t, emptyLib.MkdirAll()) + + // Check that the output of lib list and lib examples is empty + stdout, _, err := cli.Run("lib", "list", "--format", "json") + require.NoError(t, err) + requirejson.Empty(t, stdout) + + stdout, _, err = cli.Run("lib", "examples", "--format", "json") + require.NoError(t, err) + requirejson.Empty(t, stdout) + + // Create a library with a header + libWithHeader := cli.SketchbookDir().Join("libraries", "libWithHeader") + require.NoError(t, libWithHeader.MkdirAll()) + f, err := libWithHeader.Join("libWithHeader.h").Create() + require.NoError(t, err) + require.NoError(t, f.Close()) + + // Check that the output of lib list and lib examples contains the library + stdout, _, err = cli.Run("lib", "list", "--format", "json") + require.NoError(t, err) + requirejson.Len(t, stdout, 1) + + stdout, _, err = cli.Run("lib", "examples", "--format", "json") + require.NoError(t, err) + requirejson.Len(t, stdout, 1) +}