Skip to content

Commit

Permalink
Add support for default build profile (#2203)
Browse files Browse the repository at this point in the history
* 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 <c.maglie@arduino.cc>
  • Loading branch information
MatteoPologruto and cmaglie committed Aug 23, 2023
1 parent 5314a7c commit a47e35f
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 13 deletions.
6 changes: 5 additions & 1 deletion commands/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}
Expand Down
7 changes: 6 additions & 1 deletion commands/upload/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
18 changes: 16 additions & 2 deletions docs/sketch-project-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -124,15 +136,17 @@ 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:

```
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.
18 changes: 14 additions & 4 deletions internal/cli/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 != "" {
Expand Down
18 changes: 13 additions & 5 deletions internal/cli/upload/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
Expand All @@ -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],
Expand Down Expand Up @@ -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,
Expand Down
81 changes: 81 additions & 0 deletions internal/integrationtest/profiles/profiles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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" ]`)
}
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
void setup() {}
void loop() {}
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
void setup() {}
void loop() {}

0 comments on commit a47e35f

Please sign in to comment.