From c78e1d3fecf4252fef9a4b5e1ed555199cf861e6 Mon Sep 17 00:00:00 2001 From: per1234 Date: Thu, 26 Nov 2020 21:16:46 -0800 Subject: [PATCH 1/2] Add convenience function for detecting main sketch files in a path --- project/sketch/sketch.go | 26 +++++++++++++++++++ project/sketch/sketch_test.go | 13 ++++++++++ .../testdata/ContainsNoMainSketchFile/foo.bar | 0 project/sketch/testdata/Valid/Valid.ino | 2 ++ 4 files changed, 41 insertions(+) create mode 100644 project/sketch/testdata/ContainsNoMainSketchFile/foo.bar create mode 100644 project/sketch/testdata/Valid/Valid.ino diff --git a/project/sketch/sketch.go b/project/sketch/sketch.go index 382f9fc2e..cb0390d0e 100644 --- a/project/sketch/sketch.go +++ b/project/sketch/sketch.go @@ -20,6 +20,8 @@ See: https://arduino.github.io/arduino-cli/latest/sketch-specification/ package sketch import ( + "fmt" + "github.com/arduino/arduino-cli/arduino/globals" "github.com/arduino/go-paths-helper" ) @@ -31,6 +33,30 @@ func HasMainFileValidExtension(filePath *paths.Path) bool { return hasMainFileValidExtension } +// ContainsMainSketchFile checks whether the provided path contains a file with valid main sketch file extension. +func ContainsMainSketchFile(searchPath *paths.Path) bool { + if searchPath.NotExist() { + panic(fmt.Sprintf("Error: provided path %s does not exist.", searchPath)) + } + if searchPath.IsNotDir() { + panic(fmt.Sprintf("Error: provided path %s is not a directory.", searchPath)) + } + + directoryListing, err := searchPath.ReadDir() + if err != nil { + panic(err) + } + + directoryListing.FilterOutDirs() + for _, potentialHeaderFile := range directoryListing { + if HasMainFileValidExtension(potentialHeaderFile) { + return true + } + } + + return false +} + // HasSupportedExtension returns whether the file at the given path has any of the file extensions supported for source/header files of a sketch. func HasSupportedExtension(filePath *paths.Path) bool { _, hasAdditionalFileValidExtensions := globals.AdditionalFileValidExtensions[filePath.Ext()] diff --git a/project/sketch/sketch_test.go b/project/sketch/sketch_test.go index 3e724a169..aa8750c54 100644 --- a/project/sketch/sketch_test.go +++ b/project/sketch/sketch_test.go @@ -16,17 +16,30 @@ package sketch import ( + "os" "testing" "github.com/arduino/go-paths-helper" "github.com/stretchr/testify/assert" ) +var testDataPath *paths.Path + +func init() { + workingDirectory, _ := os.Getwd() + testDataPath = paths.New(workingDirectory, "testdata") +} + func TestHasMainFileValidExtension(t *testing.T) { assert.True(t, HasMainFileValidExtension(paths.New("/foo/bar.ino"))) assert.False(t, HasMainFileValidExtension(paths.New("/foo/bar.h"))) } +func TestContainsMainSketchFile(t *testing.T) { + assert.True(t, ContainsMainSketchFile(testDataPath.Join("Valid"))) + assert.False(t, ContainsMainSketchFile(testDataPath.Join("ContainsNoMainSketchFile"))) +} + func TestHasSupportedExtension(t *testing.T) { assert.True(t, HasSupportedExtension(paths.New("/foo/bar.ino"))) assert.True(t, HasSupportedExtension(paths.New("/foo/bar.h"))) diff --git a/project/sketch/testdata/ContainsNoMainSketchFile/foo.bar b/project/sketch/testdata/ContainsNoMainSketchFile/foo.bar new file mode 100644 index 000000000..e69de29bb diff --git a/project/sketch/testdata/Valid/Valid.ino b/project/sketch/testdata/Valid/Valid.ino new file mode 100644 index 000000000..660bdbccf --- /dev/null +++ b/project/sketch/testdata/Valid/Valid.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} From 0c723840a8a0ec421610a83db768fad711f530e0 Mon Sep 17 00:00:00 2001 From: per1234 Date: Thu, 26 Nov 2020 21:17:09 -0800 Subject: [PATCH 2/2] Add check for stray sketches in library --- .../checkconfigurations.go | 15 +++++++ check/checkfunctions/library.go | 40 +++++++++++++++++++ check/checkfunctions/library_test.go | 12 ++++++ .../libraries/SketchInRoot/Example.ino | 2 + .../libraries/SketchInRoot/library.properties | 9 +++++ .../libraries/SketchInRoot/src/SketchInRoot.h | 0 6 files changed, 78 insertions(+) create mode 100644 check/checkfunctions/testdata/libraries/SketchInRoot/Example.ino create mode 100644 check/checkfunctions/testdata/libraries/SketchInRoot/library.properties create mode 100644 check/checkfunctions/testdata/libraries/SketchInRoot/src/SketchInRoot.h diff --git a/check/checkconfigurations/checkconfigurations.go b/check/checkconfigurations/checkconfigurations.go index 30ed67a0f..3fadf3214 100644 --- a/check/checkconfigurations/checkconfigurations.go +++ b/check/checkconfigurations/checkconfigurations.go @@ -926,6 +926,21 @@ var configurations = []Type{ ErrorModes: nil, CheckFunction: checkfunctions.LibraryHasExe, }, + { + ProjectType: projecttype.Library, + Category: "structure", + Subcategory: "", + ID: "", + Brief: "stray sketch", + Description: "", + MessageTemplate: "Sketch(es) found outside examples and extras folders: {{.}}. See: https://arduino.github.io/arduino-cli/latest/library-specification/#library-examples", + DisableModes: nil, + EnableModes: []checkmode.Type{checkmode.All}, + InfoModes: nil, + WarningModes: []checkmode.Type{checkmode.Permissive}, + ErrorModes: []checkmode.Type{checkmode.Default}, + CheckFunction: checkfunctions.LibraryHasStraySketches, + }, { ProjectType: projecttype.Library, Category: "structure", diff --git a/check/checkfunctions/library.go b/check/checkfunctions/library.go index b466bfef2..82fdc95f5 100644 --- a/check/checkfunctions/library.go +++ b/check/checkfunctions/library.go @@ -29,6 +29,7 @@ import ( "github.com/arduino/arduino-check/check/checkresult" "github.com/arduino/arduino-check/configuration" "github.com/arduino/arduino-check/project/library" + "github.com/arduino/arduino-check/project/sketch" "github.com/arduino/arduino-cli/arduino/libraries" "github.com/arduino/arduino-cli/arduino/utils" "github.com/arduino/go-properties-orderedmap" @@ -990,6 +991,45 @@ func LibraryHasExe() (result checkresult.Type, output string) { return checkresult.Pass, "" } +// LibraryHasStraySketches checks for sketches outside the `examples` and `extras` folders. +func LibraryHasStraySketches() (result checkresult.Type, output string) { + straySketchPaths := []string{} + if sketch.ContainsMainSketchFile(checkdata.ProjectPath()) { // Check library root. + straySketchPaths = append(straySketchPaths, checkdata.ProjectPath().String()) + } + + // Check subfolders. + projectPathListing, err := checkdata.ProjectPath().ReadDir() + if err != nil { + panic(err) + } + projectPathListing.FilterDirs() + + for _, topLevelSubfolder := range projectPathListing { + if topLevelSubfolder.Base() == "examples" || topLevelSubfolder.Base() == "extras" { + continue // Skip valid sketch locations. + } + + topLevelSubfolderRecursiveListing, err := topLevelSubfolder.ReadDirRecursive() + if err != nil { + panic(err) + } + topLevelSubfolderRecursiveListing.FilterDirs() + + for _, subfolder := range topLevelSubfolderRecursiveListing { + if sketch.ContainsMainSketchFile(subfolder) { + straySketchPaths = append(straySketchPaths, subfolder.String()) + } + } + } + + if len(straySketchPaths) > 0 { + return checkresult.Fail, strings.Join(straySketchPaths, ", ") + } + + return checkresult.Pass, "" +} + // ProhibitedCharactersInLibraryFolderName checks for prohibited characters in the library folder name. func ProhibitedCharactersInLibraryFolderName() (result checkresult.Type, output string) { if !validProjectPathBaseName(checkdata.ProjectPath().Base()) { diff --git a/check/checkfunctions/library_test.go b/check/checkfunctions/library_test.go index 53c41da2f..6189bbea7 100644 --- a/check/checkfunctions/library_test.go +++ b/check/checkfunctions/library_test.go @@ -292,6 +292,18 @@ func TestLibraryHasExe(t *testing.T) { checkLibraryCheckFunction(LibraryHasExe, testTables, t) } + +func TestLibraryHasStraySketches(t *testing.T) { + testTables := []libraryCheckFunctionTestTable{ + {"Sketch in root", "SketchInRoot", checkresult.Fail, ""}, + {"Sketch in subfolder", "MisspelledExamplesFolder", checkresult.Fail, ""}, + {"Sketch in legit location", "ExamplesFolder", checkresult.Pass, ""}, + {"No sketches", "Recursive", checkresult.Pass, ""}, + } + + checkLibraryCheckFunction(LibraryHasStraySketches, testTables, t) +} + func TestProhibitedCharactersInLibraryFolderName(t *testing.T) { testTables := []libraryCheckFunctionTestTable{ {"Has prohibited characters", "Prohibited CharactersInFolderName", checkresult.Fail, ""}, diff --git a/check/checkfunctions/testdata/libraries/SketchInRoot/Example.ino b/check/checkfunctions/testdata/libraries/SketchInRoot/Example.ino new file mode 100644 index 000000000..660bdbccf --- /dev/null +++ b/check/checkfunctions/testdata/libraries/SketchInRoot/Example.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} diff --git a/check/checkfunctions/testdata/libraries/SketchInRoot/library.properties b/check/checkfunctions/testdata/libraries/SketchInRoot/library.properties new file mode 100644 index 000000000..726aaaf6c --- /dev/null +++ b/check/checkfunctions/testdata/libraries/SketchInRoot/library.properties @@ -0,0 +1,9 @@ +name=SketchInRoot +version=1.0.0 +author=Cristian Maglie , Pippo Pluto +maintainer=Cristian Maglie +sentence=A library that makes coding a web server a breeze. +paragraph=Supports HTTP1.1 and you can do GET and POST. +category=Communication +url=http://example.com/ +architectures=avr diff --git a/check/checkfunctions/testdata/libraries/SketchInRoot/src/SketchInRoot.h b/check/checkfunctions/testdata/libraries/SketchInRoot/src/SketchInRoot.h new file mode 100644 index 000000000..e69de29bb