Skip to content

Commit 80b0018

Browse files
committed
Implementation of profile commands
1 parent c537b5a commit 80b0018

File tree

7 files changed

+458
-0
lines changed

7 files changed

+458
-0
lines changed

internal/cli/cli.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"github.com/arduino/arduino-cli/internal/cli/lib"
3737
"github.com/arduino/arduino-cli/internal/cli/monitor"
3838
"github.com/arduino/arduino-cli/internal/cli/outdated"
39+
"github.com/arduino/arduino-cli/internal/cli/profile"
3940
"github.com/arduino/arduino-cli/internal/cli/sketch"
4041
"github.com/arduino/arduino-cli/internal/cli/update"
4142
"github.com/arduino/arduino-cli/internal/cli/updater"
@@ -162,6 +163,7 @@ func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
162163
cmd.AddCommand(burnbootloader.NewCommand(srv))
163164
cmd.AddCommand(version.NewCommand(srv))
164165
cmd.AddCommand(feedback.NewCommand())
166+
cmd.AddCommand(profile.NewCommand(srv))
165167

166168
cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, i18n.Tr("Print the logs on the standard output."))
167169
cmd.Flag("verbose").Hidden = true

internal/cli/profile/profile.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2025 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package profile
17+
18+
import (
19+
"os"
20+
21+
"github.com/arduino/arduino-cli/internal/cli/arguments"
22+
"github.com/arduino/arduino-cli/internal/i18n"
23+
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
24+
"github.com/spf13/cobra"
25+
)
26+
27+
var (
28+
fqbnArg arguments.Fqbn // Fully Qualified Board Name, e.g.: arduino:avr:uno.
29+
profileArg arguments.Profile // Name of the profile to add to the project
30+
)
31+
32+
func NewCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
33+
profileCommand := &cobra.Command{
34+
Use: "profile",
35+
Short: i18n.Tr("Build profile operations."),
36+
Long: i18n.Tr("Build profile operations."),
37+
Example: " " + os.Args[0] + " profile init",
38+
}
39+
40+
profileCommand.AddCommand(initProfileCreateCommand(srv))
41+
profileCommand.AddCommand(initProfileLibCommand(srv))
42+
profileCommand.AddCommand(initProfileSetDefaultCommand(srv))
43+
// profileCommand.AddCommand(initDumpCommand(srv))
44+
45+
return profileCommand
46+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2025 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package profile
17+
18+
import (
19+
"context"
20+
"os"
21+
22+
"github.com/arduino/arduino-cli/internal/cli/arguments"
23+
"github.com/arduino/arduino-cli/internal/cli/feedback"
24+
"github.com/arduino/arduino-cli/internal/cli/instance"
25+
"github.com/arduino/arduino-cli/internal/i18n"
26+
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
27+
"github.com/arduino/go-paths-helper"
28+
"github.com/spf13/cobra"
29+
)
30+
31+
func initProfileCreateCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
32+
var defaultProfile bool
33+
initCommand := &cobra.Command{
34+
Use: "init",
35+
Short: i18n.Tr("Create or update the sketch project file."),
36+
Long: i18n.Tr("Create or update the sketch project file."),
37+
Example: "" +
38+
" # " + i18n.Tr("Creates or updates the sketch project file in the current directory.") + "\n" +
39+
" " + os.Args[0] + " profile init\n" +
40+
" " + os.Args[0] + " profile init --profile uno_profile -b arduino:avr:uno",
41+
Args: cobra.MaximumNArgs(1),
42+
Run: func(cmd *cobra.Command, args []string) {
43+
runInitCommand(cmd.Context(), args, srv, defaultProfile)
44+
},
45+
}
46+
fqbnArg.AddToCommand(initCommand, srv)
47+
profileArg.AddToCommand(initCommand, srv)
48+
initCommand.Flags().BoolVar(&defaultProfile, "default", false, i18n.Tr("Set the profile as the default one."))
49+
return initCommand
50+
}
51+
52+
func runInitCommand(ctx context.Context, args []string, srv rpc.ArduinoCoreServiceServer, defaultProfile bool) {
53+
path := ""
54+
if len(args) > 0 {
55+
path = args[0]
56+
}
57+
58+
sketchPath := arguments.InitSketchPath(path)
59+
60+
inst := instance.CreateAndInit(ctx, srv)
61+
62+
_, err := srv.ProfileCreate(ctx, &rpc.ProfileCreateRequest{
63+
Instance: inst,
64+
SketchPath: sketchPath.String(),
65+
ProfileName: profileArg.Get(),
66+
Fqbn: fqbnArg.String(),
67+
DefaultProfile: defaultProfile})
68+
if err != nil {
69+
feedback.Fatal(i18n.Tr("Error initializing the project file: %v", err), feedback.ErrGeneric)
70+
}
71+
feedback.PrintResult(profileResult{ProjectFilePath: sketchPath.Join("sketch.yaml")})
72+
}
73+
74+
type profileResult struct {
75+
ProjectFilePath *paths.Path `json:"project_path"`
76+
}
77+
78+
func (ir profileResult) Data() interface{} {
79+
return ir
80+
}
81+
82+
func (ir profileResult) String() string {
83+
return i18n.Tr("Project file created in: %s", ir.ProjectFilePath)
84+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2025 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package profile
17+
18+
import (
19+
"os"
20+
21+
"github.com/arduino/arduino-cli/internal/i18n"
22+
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
23+
"github.com/spf13/cobra"
24+
)
25+
26+
func initProfileLibCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
27+
libCommand := &cobra.Command{
28+
Use: "lib",
29+
Short: i18n.Tr("Commands related to build profile libraries."),
30+
Long: i18n.Tr("Commands related to the library dependencies of build profiles."),
31+
Example: "" +
32+
" " + os.Args[0] + " profile lib add AudioZero -m my_profile\n" +
33+
" " + os.Args[0] + " profile lib remove Arduino_JSON --profile my_profile\n",
34+
}
35+
36+
libCommand.AddCommand(initLibAddCommand(srv))
37+
libCommand.AddCommand(initLibRemoveCommand(srv))
38+
39+
return libCommand
40+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2025 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package profile
17+
18+
import (
19+
"context"
20+
"fmt"
21+
"os"
22+
23+
"github.com/arduino/arduino-cli/internal/cli/arguments"
24+
"github.com/arduino/arduino-cli/internal/cli/feedback"
25+
"github.com/arduino/arduino-cli/internal/cli/feedback/result"
26+
"github.com/arduino/arduino-cli/internal/cli/instance"
27+
"github.com/arduino/arduino-cli/internal/cli/lib"
28+
"github.com/arduino/arduino-cli/internal/i18n"
29+
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
30+
"github.com/spf13/cobra"
31+
"go.bug.st/f"
32+
)
33+
34+
func initLibAddCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
35+
var destDir string
36+
var noDeps bool
37+
var noOverwrite bool
38+
addCommand := &cobra.Command{
39+
Use: fmt.Sprintf("add %s[@%s]...", i18n.Tr("LIBRARY"), i18n.Tr("VERSION_NUMBER")),
40+
Short: i18n.Tr("Adds a library to the profile."),
41+
Long: i18n.Tr("Adds a library to the profile."),
42+
Example: "" +
43+
" " + os.Args[0] + " profile lib add AudioZero -m my_profile\n" +
44+
" " + os.Args[0] + " profile lib add [email protected] --profile my_profile\n",
45+
Args: cobra.MinimumNArgs(1),
46+
Run: func(cmd *cobra.Command, args []string) {
47+
runLibAddCommand(cmd.Context(), args, srv, destDir, noDeps, noOverwrite)
48+
},
49+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
50+
return arguments.GetInstallableLibs(cmd.Context(), srv), cobra.ShellCompDirectiveDefault
51+
},
52+
}
53+
54+
addCommand.Flags().StringVar(&destDir, "dest-dir", "", i18n.Tr("Location of the sketch project file."))
55+
addCommand.Flags().BoolVar(&noDeps, "no-deps", false, i18n.Tr("Do not add dependencies."))
56+
addCommand.Flags().BoolVar(&noOverwrite, "no-overwrite", false, i18n.Tr("Do not overwrite already added libraries."))
57+
58+
profileArg.AddToCommand(addCommand, srv)
59+
60+
return addCommand
61+
}
62+
63+
func runLibAddCommand(ctx context.Context, args []string, srv rpc.ArduinoCoreServiceServer, destDir string, noAddDeps, noOverwrite bool) {
64+
sketchPath := arguments.InitSketchPath(destDir)
65+
66+
instance := instance.CreateAndInit(ctx, srv)
67+
libRefs, err := lib.ParseLibraryReferenceArgsAndAdjustCase(ctx, srv, instance, args)
68+
if err != nil {
69+
feedback.Fatal(i18n.Tr("Arguments error: %v", err), feedback.ErrBadArgument)
70+
}
71+
addDeps := !noAddDeps
72+
for _, lib := range libRefs {
73+
resp, err := srv.ProfileLibAdd(ctx, &rpc.ProfileLibAddRequest{
74+
Instance: instance,
75+
SketchPath: sketchPath.String(),
76+
ProfileName: profileArg.Get(),
77+
Library: &rpc.ProfileLibraryReference{
78+
Library: &rpc.ProfileLibraryReference_IndexLibrary_{
79+
IndexLibrary: &rpc.ProfileLibraryReference_IndexLibrary{
80+
Name: lib.Name,
81+
Version: lib.Version,
82+
},
83+
},
84+
},
85+
AddDependencies: &addDeps,
86+
NoOverwrite: &noOverwrite,
87+
})
88+
if err != nil {
89+
feedback.Fatal(i18n.Tr("Error adding %s to the profile %s: %v", lib.Name, profileArg.Get(), err), feedback.ErrGeneric)
90+
}
91+
feedback.PrintResult(libAddResult{
92+
AddedLibraries: f.Map(resp.GetAddedLibraries(), result.NewProfileLibraryReference),
93+
SkippedLibraries: f.Map(resp.GetSkippedLibraries(), result.NewProfileLibraryReference),
94+
ProfileName: resp.ProfileName,
95+
})
96+
}
97+
}
98+
99+
type libAddResult struct {
100+
AddedLibraries []*result.ProfileLibraryReference `json:"added_libraries"`
101+
SkippedLibraries []*result.ProfileLibraryReference `json:"skipped_libraries"`
102+
ProfileName string `json:"profile_name"`
103+
}
104+
105+
func (lr libAddResult) Data() any {
106+
return lr
107+
}
108+
109+
func (lr libAddResult) String() string {
110+
res := ""
111+
if len(lr.AddedLibraries) > 0 {
112+
res += fmt.Sprintln(i18n.Tr("The following libraries were added to the profile %s:", lr.ProfileName))
113+
for _, l := range lr.AddedLibraries {
114+
res += fmt.Sprintf(" - %s\n", l)
115+
}
116+
}
117+
if len(lr.SkippedLibraries) > 0 {
118+
res += fmt.Sprintln(i18n.Tr("The following libraries were already present in the profile %s and were not modified:", lr.ProfileName))
119+
for _, l := range lr.SkippedLibraries {
120+
res += fmt.Sprintf(" - %s\n", l)
121+
}
122+
}
123+
return res
124+
}

0 commit comments

Comments
 (0)