From b748aeca78016147ce97b42eee5e3d1f5e72cd70 Mon Sep 17 00:00:00 2001 From: MatteoPologruto <109663225+MatteoPologruto@users.noreply.github.com> Date: Wed, 23 Aug 2023 13:25:05 +0200 Subject: [PATCH] Add support for default build profile (#2203) * Add support for default profile to compile command * Add support for default profiles to upload command * Add TestCompileWithDefaultProfile to integration tests * Get the profile's FQBN if it's not already specified in the request * Update documentation regarding sketch projects * Added integration tests for all default_profile cases * Reverted old sketch_with_profile test --------- Co-authored-by: Cristian Maglie --- commands/compile/compile.go | 6 +- commands/upload/upload.go | 7 +- docs/sketch-project-file.md | 18 ++++- internal/cli/compile/compile.go | 18 ++++- internal/cli/upload/upload.go | 18 +++-- .../integrationtest/profiles/profiles_test.go | 81 +++++++++++++++++++ .../sketch_with_default_profile/sketch.yaml | 12 +++ .../sketch_with_default_profile.ino | 2 + .../sketch.yaml | 10 +++ .../sketch_without_default_profile.ino | 2 + 10 files changed, 161 insertions(+), 13 deletions(-) create mode 100644 internal/integrationtest/testdata/sketch_with_default_profile/sketch.yaml create mode 100644 internal/integrationtest/testdata/sketch_with_default_profile/sketch_with_default_profile.ino create mode 100644 internal/integrationtest/testdata/sketch_without_default_profile/sketch.yaml create mode 100644 internal/integrationtest/testdata/sketch_without_default_profile/sketch_without_default_profile.ino diff --git a/commands/compile/compile.go b/commands/compile/compile.go index ba904fddad0..92858dd68d6 100644 --- a/commands/compile/compile.go +++ b/commands/compile/compile.go @@ -81,7 +81,11 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream fqbnIn := req.GetFqbn() if fqbnIn == "" && sk != nil { - fqbnIn = sk.GetDefaultFQBN() + if pme.GetProfile() != nil { + fqbnIn = pme.GetProfile().FQBN + } else { + fqbnIn = sk.GetDefaultFQBN() + } } if fqbnIn == "" { return nil, &arduino.MissingFQBNError{} diff --git a/commands/upload/upload.go b/commands/upload/upload.go index 5fe21089848..0bf0ae86ec0 100644 --- a/commands/upload/upload.go +++ b/commands/upload/upload.go @@ -143,12 +143,17 @@ func Upload(ctx context.Context, req *rpc.UploadRequest, outStream io.Writer, er } defer pmeRelease() + fqbn := req.GetFqbn() + if fqbn == "" && pme.GetProfile() != nil { + fqbn = pme.GetProfile().FQBN + } + updatedPort, err := runProgramAction( pme, sk, req.GetImportFile(), req.GetImportDir(), - req.GetFqbn(), + fqbn, req.GetPort(), req.GetProgrammer(), req.GetVerbose(), diff --git a/docs/sketch-project-file.md b/docs/sketch-project-file.md index 01a5607c8db..640ede7505e 100644 --- a/docs/sketch-project-file.md +++ b/docs/sketch-project-file.md @@ -95,6 +95,8 @@ profiles: - ArduinoIoTCloud (1.0.2) - Arduino_ConnectionHandler (0.6.4) - TinyDHT sensor library (1.1.0) + +default_profile: nanorp ``` ### Building a sketch @@ -116,6 +118,16 @@ not be used in any way. In other words, the build is isolated from the system an specified in the profile: this will ensure that the build is portable and reproducible independently from the platforms and libraries installed in the system. +### Using a default profile + +If a `default_profile` is specified in the `sketch.yaml` then the “classic” compile command: + +``` +arduino-cli compile [sketch] +``` + +will, instead, trigger a profile-based build using the default profile indicated in the `sketch.yaml`. + ## Default flags for Arduino CLI usage The sketch project file may be used to set the default value for some command line flags of the Arduino CLI, in @@ -124,6 +136,7 @@ particular: - The `default_fqbn` key sets the default value for the `--fqbn` flag - The `default_port` key sets the default value for the `--port` flag - The `default_protocol` key sets the default value for the `--protocol` flag +- The `default_profile` key sets the default value for the `--profile` flag For example: @@ -131,8 +144,9 @@ For example: default_fqbn: arduino:avr:uno default_port: /dev/ttyACM0 default_protocol: serial +default_profile: myprofile ``` -With this configuration set, it is not necessary to specify the `--fqbn`, `--port`, or `--protocol` flags to the -[`arduino-cli compile`](commands/arduino-cli_compile.md) or [`arduino-cli upload`](commands/arduino-cli_upload.md) +With this configuration set, it is not necessary to specify the `--fqbn`, `--port`, `--protocol` or `--profile` flags to +the [`arduino-cli compile`](commands/arduino-cli_compile.md) or [`arduino-cli upload`](commands/arduino-cli_upload.md) commands when compiling or uploading the sketch. diff --git a/internal/cli/compile/compile.go b/internal/cli/compile/compile.go index baa1dff5f89..dfd5d4c70ba 100644 --- a/internal/cli/compile/compile.go +++ b/internal/cli/compile/compile.go @@ -159,15 +159,25 @@ func runCompileCommand(cmd *cobra.Command, args []string) { } sketchPath := arguments.InitSketchPath(path) - inst, profile := instance.CreateAndInitWithProfile(profileArg.Get(), sketchPath) - if fqbnArg.String() == "" { - fqbnArg.Set(profile.GetFqbn()) - } sk, err := sketch.LoadSketch(context.Background(), &rpc.LoadSketchRequest{SketchPath: sketchPath.String()}) if err != nil { feedback.FatalError(err, feedback.ErrGeneric) } + + var inst *rpc.Instance + var profile *rpc.Profile + + if profileArg.Get() == "" { + inst, profile = instance.CreateAndInitWithProfile(sk.GetDefaultProfile().GetName(), sketchPath) + } else { + inst, profile = instance.CreateAndInitWithProfile(profileArg.Get(), sketchPath) + } + + if fqbnArg.String() == "" { + fqbnArg.Set(profile.GetFqbn()) + } + fqbn, port := arguments.CalculateFQBNAndPort(&portArgs, &fqbnArg, inst, sk.GetDefaultFqbn(), sk.GetDefaultPort(), sk.GetDefaultProtocol()) if keysKeychain != "" || signKey != "" || encryptKey != "" { diff --git a/internal/cli/upload/upload.go b/internal/cli/upload/upload.go index 1fa91086ac0..0f2a798d979 100644 --- a/internal/cli/upload/upload.go +++ b/internal/cli/upload/upload.go @@ -95,17 +95,25 @@ func runUploadCommand(command *cobra.Command, args []string) { feedback.Fatal(tr("Error during Upload: %v", err), feedback.ErrGeneric) } - instance, profile := instance.CreateAndInitWithProfile(profileArg.Get(), sketchPath) + var inst *rpc.Instance + var profile *rpc.Profile + + if profileArg.Get() == "" { + inst, profile = instance.CreateAndInitWithProfile(sk.Project.DefaultProfile, sketchPath) + } else { + inst, profile = instance.CreateAndInitWithProfile(profileArg.Get(), sketchPath) + } + if fqbnArg.String() == "" { fqbnArg.Set(profile.GetFqbn()) } defaultFQBN := sk.GetDefaultFQBN() defaultAddress, defaultProtocol := sk.GetDefaultPortAddressAndProtocol() - fqbn, port := arguments.CalculateFQBNAndPort(&portArgs, &fqbnArg, instance, defaultFQBN, defaultAddress, defaultProtocol) + fqbn, port := arguments.CalculateFQBNAndPort(&portArgs, &fqbnArg, inst, defaultFQBN, defaultAddress, defaultProtocol) userFieldRes, err := upload.SupportedUserFields(context.Background(), &rpc.SupportedUserFieldsRequest{ - Instance: instance, + Instance: inst, Fqbn: fqbn, Protocol: port.Protocol, }) @@ -122,7 +130,7 @@ func runUploadCommand(command *cobra.Command, args []string) { } // FIXME: Here we must not access package manager... - pme, release := commands.GetPackageManagerExplorer(&rpc.UploadRequest{Instance: instance}) + pme, release := commands.GetPackageManagerExplorer(&rpc.UploadRequest{Instance: inst}) platform := pme.FindPlatform(&packagemanager.PlatformReference{ Package: split[0], PlatformArchitecture: split[1], @@ -156,7 +164,7 @@ func runUploadCommand(command *cobra.Command, args []string) { stdOut, stdErr, stdIOResult := feedback.OutputStreams() req := &rpc.UploadRequest{ - Instance: instance, + Instance: inst, Fqbn: fqbn, SketchPath: path, Port: port, diff --git a/internal/integrationtest/profiles/profiles_test.go b/internal/integrationtest/profiles/profiles_test.go index 9cd1ffcb556..4915bed5cf7 100644 --- a/internal/integrationtest/profiles/profiles_test.go +++ b/internal/integrationtest/profiles/profiles_test.go @@ -20,6 +20,7 @@ import ( "github.com/arduino/arduino-cli/internal/integrationtest" "github.com/stretchr/testify/require" + "go.bug.st/testifyjson/requirejson" ) func TestCompileWithProfiles(t *testing.T) { @@ -69,3 +70,83 @@ func TestBuilderDidNotCatchLibsFromUnusedPlatforms(t *testing.T) { require.NotContains(t, string(stdout), "samd") require.NotContains(t, string(stderr), "samd") } + +func TestCompileWithDefaultProfile(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + // Init the environment explicitly + _, _, err := cli.Run("core", "update-index") + require.NoError(t, err) + + // Installa core/libs globally + _, _, err = cli.Run("core", "install", "arduino:avr@1.8.3") + require.NoError(t, err) + + // copy sketch_with_profile into the working directory + sketchWithoutDefProfilePath := cli.CopySketch("sketch_without_default_profile") + sketchWithDefProfilePath := cli.CopySketch("sketch_with_default_profile") + + { + // no default profile -> error missing FQBN + _, _, err := cli.Run("compile", sketchWithoutDefProfilePath.String(), "--format", "json") + require.Error(t, err) + } + { + // specified fbqn -> compile with specified FQBN and use global installation + stdout, _, err := cli.Run("compile", "-b", "arduino:avr:nano", sketchWithoutDefProfilePath.String(), "--format", "json") + require.NoError(t, err) + jsonOut := requirejson.Parse(t, stdout) + jsonOut.Query(".builder_result.build_platform").MustContain(`{"id":"arduino:avr", "version":"1.8.3"}`) + jsonOut.Query(".builder_result.build_properties").MustContain(`[ "build.fqbn=arduino:avr:nano" ]`) + } + { + // specified profile -> use the specified profile + stdout, _, err := cli.Run("compile", "--profile", "avr1", sketchWithoutDefProfilePath.String(), "--format", "json") + require.NoError(t, err) + jsonOut := requirejson.Parse(t, stdout) + jsonOut.Query(".builder_result.build_platform").MustContain(`{"id":"arduino:avr", "version":"1.8.4"}`) + jsonOut.Query(".builder_result.build_properties").MustContain(`[ "build.fqbn=arduino:avr:uno" ]`) + } + { + // specified profile and fqbn -> use the specified profile and override fqbn + stdout, _, err := cli.Run("compile", "--profile", "avr1", "-b", "arduino:avr:nano", sketchWithoutDefProfilePath.String(), "--format", "json") + require.NoError(t, err) + jsonOut := requirejson.Parse(t, stdout) + jsonOut.Query(".builder_result.build_platform").MustContain(`{"id":"arduino:avr", "version":"1.8.4"}`) + jsonOut.Query(".builder_result.build_properties").MustContain(`[ "build.fqbn=arduino:avr:nano" ]`) + } + + { + // default profile -> use default profile + stdout, _, err := cli.Run("compile", sketchWithDefProfilePath.String(), "--format", "json") + require.NoError(t, err) + jsonOut := requirejson.Parse(t, stdout) + jsonOut.Query(".builder_result.build_platform").MustContain(`{"id":"arduino:avr", "version":"1.8.5"}`) + jsonOut.Query(".builder_result.build_properties").MustContain(`[ "build.fqbn=arduino:avr:leonardo" ]`) + } + { + // default profile, specified fbqn -> use default profile, override fqbn + stdout, _, err := cli.Run("compile", "-b", "arduino:avr:nano", sketchWithDefProfilePath.String(), "--format", "json") + require.NoError(t, err) + jsonOut := requirejson.Parse(t, stdout) + jsonOut.Query(".builder_result.build_platform").MustContain(`{"id":"arduino:avr", "version":"1.8.5"}`) + jsonOut.Query(".builder_result.build_properties").MustContain(`[ "build.fqbn=arduino:avr:nano" ]`) + } + { + // default profile, specified different profile -> use the specified profile + stdout, _, err := cli.Run("compile", "--profile", "avr1", sketchWithDefProfilePath.String(), "--format", "json") + require.NoError(t, err) + jsonOut := requirejson.Parse(t, stdout) + jsonOut.Query(".builder_result.build_platform").MustContain(`{"id":"arduino:avr", "version":"1.8.4"}`) + jsonOut.Query(".builder_result.build_properties").MustContain(`[ "build.fqbn=arduino:avr:uno" ]`) + } + { + // default profile, specified different profile and fqbn -> use the specified profile and override fqbn + stdout, _, err := cli.Run("compile", "--profile", "avr1", "-b", "arduino:avr:nano", sketchWithDefProfilePath.String(), "--format", "json") + require.NoError(t, err) + jsonOut := requirejson.Parse(t, stdout) + jsonOut.Query(".builder_result.build_platform").MustContain(`{"id":"arduino:avr", "version":"1.8.4"}`) + jsonOut.Query(".builder_result.build_properties").MustContain(`[ "build.fqbn=arduino:avr:nano" ]`) + } +} diff --git a/internal/integrationtest/testdata/sketch_with_default_profile/sketch.yaml b/internal/integrationtest/testdata/sketch_with_default_profile/sketch.yaml new file mode 100644 index 00000000000..95d13d5754e --- /dev/null +++ b/internal/integrationtest/testdata/sketch_with_default_profile/sketch.yaml @@ -0,0 +1,12 @@ +profiles: + avr1: + fqbn: arduino:avr:uno + platforms: + - platform: arduino:avr (1.8.4) + + avr2: + fqbn: arduino:avr:leonardo + platforms: + - platform: arduino:avr (1.8.5) + +default_profile: avr2 diff --git a/internal/integrationtest/testdata/sketch_with_default_profile/sketch_with_default_profile.ino b/internal/integrationtest/testdata/sketch_with_default_profile/sketch_with_default_profile.ino new file mode 100644 index 00000000000..660bdbccfdb --- /dev/null +++ b/internal/integrationtest/testdata/sketch_with_default_profile/sketch_with_default_profile.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {} diff --git a/internal/integrationtest/testdata/sketch_without_default_profile/sketch.yaml b/internal/integrationtest/testdata/sketch_without_default_profile/sketch.yaml new file mode 100644 index 00000000000..1344a8fa507 --- /dev/null +++ b/internal/integrationtest/testdata/sketch_without_default_profile/sketch.yaml @@ -0,0 +1,10 @@ +profiles: + avr1: + fqbn: arduino:avr:uno + platforms: + - platform: arduino:avr (1.8.4) + + avr2: + fqbn: arduino:avr:leonardo + platforms: + - platform: arduino:avr (1.8.5) diff --git a/internal/integrationtest/testdata/sketch_without_default_profile/sketch_without_default_profile.ino b/internal/integrationtest/testdata/sketch_without_default_profile/sketch_without_default_profile.ino new file mode 100644 index 00000000000..660bdbccfdb --- /dev/null +++ b/internal/integrationtest/testdata/sketch_without_default_profile/sketch_without_default_profile.ino @@ -0,0 +1,2 @@ +void setup() {} +void loop() {}