Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for default build profile #2203

Merged
merged 7 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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:[email protected]")
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() {}