From a71415facd42d9384e4ac3f34a943b5b31ac9b72 Mon Sep 17 00:00:00 2001 From: MatteoPologruto <109663225+MatteoPologruto@users.noreply.github.com> Date: Tue, 20 Jun 2023 08:38:50 +0200 Subject: [PATCH] [breaking] Check cross-platform compatibility of sketch names (#2216) * Exclude sketch names ending with a dot * Fail with error if a reserved name is used as sketch name * Update sketch name specifications in docs --- commands/sketch/new.go | 12 ++++++++++-- commands/sketch/new_test.go | 16 ++++++++++++++-- docs/UPGRADING.md | 7 +++++++ docs/sketch-specification.md | 4 +++- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/commands/sketch/new.go b/commands/sketch/new.go index ff2828b4e6f..b4fe3ab0e82 100644 --- a/commands/sketch/new.go +++ b/commands/sketch/new.go @@ -37,7 +37,10 @@ void loop() { // sketchNameMaxLength could be part of the regex, but it's intentionally left out for clearer error reporting var sketchNameMaxLength = 63 -var sketchNameValidationRegex = regexp.MustCompile(`^[0-9a-zA-Z_][0-9a-zA-Z_\.-]*$`) +var sketchNameValidationRegex = regexp.MustCompile(`^[0-9a-zA-Z_](?:[0-9a-zA-Z_\.-]*[0-9a-zA-Z_-]|)$`) + +var invalidNames = []string{"CON", "PRN", "AUX", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", + "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"} // NewSketch creates a new sketch via gRPC func NewSketch(ctx context.Context, req *rpc.NewSketchRequest) (*rpc.NewSketchResponse, error) { @@ -80,8 +83,13 @@ func validateSketchName(name string) error { sketchNameMaxLength))} } if !sketchNameValidationRegex.MatchString(name) { - return &arduino.CantCreateSketchError{Cause: errors.New(tr(`invalid sketch name "%[1]s": the first character must be alphanumeric or "_", the following ones can also contain "-" and ".".`, + return &arduino.CantCreateSketchError{Cause: errors.New(tr(`invalid sketch name "%[1]s": the first character must be alphanumeric or "_", the following ones can also contain "-" and ".". The last one cannot be ".".`, name))} } + for _, invalid := range invalidNames { + if name == invalid { + return &arduino.CantCreateSketchError{Cause: errors.New(tr(`sketch name cannot be the reserved name "%[1]s"`, invalid))} + } + } return nil } diff --git a/commands/sketch/new_test.go b/commands/sketch/new_test.go index a0812448c6f..00ae7856732 100644 --- a/commands/sketch/new_test.go +++ b/commands/sketch/new_test.go @@ -30,6 +30,7 @@ func Test_SketchNameWrongPattern(t *testing.T) { ".hello", "-hello", "hello*", + "hello.", "||||||||||||||", ",`hack[}attempt{];", } @@ -39,7 +40,7 @@ func Test_SketchNameWrongPattern(t *testing.T) { SketchDir: t.TempDir(), }) - require.EqualError(t, err, fmt.Sprintf(`Can't create sketch: invalid sketch name "%s": the first character must be alphanumeric or "_", the following ones can also contain "-" and ".".`, + require.EqualError(t, err, fmt.Sprintf(`Can't create sketch: invalid sketch name "%s": the first character must be alphanumeric or "_", the following ones can also contain "-" and ".". The last one cannot be ".".`, name)) } } @@ -78,7 +79,6 @@ func Test_SketchNameOk(t *testing.T) { "h", "h.ello", "h..ello-world", - "h..ello-world.", "hello_world__", "_hello_world", string(lengthLimitName), @@ -91,3 +91,15 @@ func Test_SketchNameOk(t *testing.T) { require.Nil(t, err) } } + +func Test_SketchNameReserved(t *testing.T) { + invalidNames := []string{"CON", "PRN", "AUX", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", + "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"} + for _, name := range invalidNames { + _, err := NewSketch(context.Background(), &commands.NewSketchRequest{ + SketchName: name, + SketchDir: t.TempDir(), + }) + require.EqualError(t, err, fmt.Sprintf(`Can't create sketch: sketch name cannot be the reserved name "%s"`, name)) + } +} diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index 39d0ef5b992..63071bb2f50 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -4,6 +4,13 @@ Here you can find a list of migration guides to handle breaking changes between ## 0.34.0 +### Updated sketch name specifications + +[Sketch name specifications](https://arduino.github.io/arduino-cli/dev/sketch-specification) have been updated to +achieve cross-platform compatibility. + +Existing sketch names violating the new constraint need to be updated. + ### golang API: `LoadSketch` function has been moved The function `github.com/arduino/arduino-cli/commands.LoadSketch` has been moved to package diff --git a/docs/sketch-specification.md b/docs/sketch-specification.md index f7488c794ca..316787476c6 100644 --- a/docs/sketch-specification.md +++ b/docs/sketch-specification.md @@ -7,7 +7,9 @@ The programs that run on Arduino boards are called "sketches". This term was inh The sketch root folder name and code file names must start with a basic letter (`A`-`Z` or `a`-`z`), number (`0`-`9`) [1](#leading-number-note), or underscore (`_`) [2](#leading-underscore-note) followed by basic -letters, numbers, underscores, dots (`.`) and dashes (`-`). The maximum length is 63 characters. +letters, numbers, underscores, dots (`.`) and dashes (`-`). The maximum length is 63 characters. The sketch name cannot +end with a dot (`.`) and cannot be a +[reserved name](https://learn.microsoft.com/windows/win32/fileio/naming-a-file#naming-conventions). 1 Supported from Arduino IDE 1.8.4.
2 Supported in all versions except Arduino IDE 2.0.4/Arduino CLI