diff --git a/cmd/arduino-app-cli/board/board.go b/cmd/arduino-app-cli/board/board.go deleted file mode 100644 index 98b3c04b..00000000 --- a/cmd/arduino-app-cli/board/board.go +++ /dev/null @@ -1,306 +0,0 @@ -// This file is part of arduino-app-cli. -// -// Copyright 2025 ARDUINO SA (http://www.arduino.cc/) -// -// This software is released under the GNU General Public License version 3, -// which covers the main part of arduino-app-cli. -// The terms of this license can be found at: -// https://www.gnu.org/licenses/gpl-3.0.en.html -// -// You can be released from the requirements of the above licenses by purchasing -// a commercial license. Buying such a license is mandatory if you want to -// modify or otherwise use the software for commercial activities involving the -// Arduino software without disclosing the source code of your own applications. -// To purchase a commercial license, send an email to license@arduino.cc. - -package board - -import ( - "context" - "fmt" - "os" - "strconv" - - "github.com/spf13/cobra" - "golang.org/x/term" - - "github.com/arduino/arduino-app-cli/cmd/feedback" - "github.com/arduino/arduino-app-cli/pkg/board" - "github.com/arduino/arduino-app-cli/pkg/board/remote" - "github.com/arduino/arduino-app-cli/pkg/board/remote/adb" -) - -type contextKey string - -const remoteConnKey contextKey = "remoteConn" -const boardsListKey contextKey = "boardsList" - -func NewBoardCmd() *cobra.Command { - var fqbn, host string - fsCmd := &cobra.Command{ - Use: "board", - Short: "Manage boards", - Long: "", - Hidden: true, - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - if host != "" { - conn, err := adb.FromHost(host, "") - if err != nil { - panic(fmt.Errorf("failed to connect to ADB host %s: %w", host, err)) - } - cmd.SetContext(context.WithValue(cmd.Context(), remoteConnKey, conn)) - return nil - } - - boards, err := board.FromFQBN(cmd.Context(), fqbn) - if err != nil { - return fmt.Errorf("failed to get boards for FQBN %s: %w", fqbn, err) - } - if len(boards) == 0 { - return fmt.Errorf("no boards found for FQBN %s", fqbn) - } - conn, err := boards[0].GetConnection() - if err != nil { - return fmt.Errorf("failed to connect to board %s: %w", boards[0].BoardName, err) - } - - cmd.SetContext(context.WithValue(cmd.Context(), remoteConnKey, conn)) - cmd.SetContext(context.WithValue(cmd.Context(), boardsListKey, boards)) - return nil - }, - } - fsCmd.PersistentFlags().StringVarP(&fqbn, "fqbn", "b", "arduino:zephyr:unoq", "fqbn of the board") - fsCmd.PersistentFlags().StringVar(&host, "host", "", "ADB host address") - - fsCmd.AddCommand(newBoardListCmd()) - fsCmd.AddCommand(newBoardSetName()) - fsCmd.AddCommand(newSetPasswordCmd()) - fsCmd.AddCommand(newEnableNetworkModeCmd()) - fsCmd.AddCommand(newDisableNetworkModeCmd()) - fsCmd.AddCommand(newNetworkModeStatusCmd()) - - fsCmd.AddCommand(listKeyboardLayouts()) - fsCmd.AddCommand(getKeyboardLayout()) - fsCmd.AddCommand(setKeyboardLayout()) - - return fsCmd -} - -func newBoardListCmd() *cobra.Command { - listCmd := &cobra.Command{ - Use: "list", - Short: "List available boards", - RunE: func(cmd *cobra.Command, args []string) error { - boards := cmd.Context().Value(boardsListKey).([]board.Board) - for _, b := range boards { - - var address, configured string - switch b.Protocol { - case board.SerialProtocol, board.LocalProtocol: - address = b.Serial - - if conn, err := b.GetConnection(); err != nil { - return fmt.Errorf("failed to connect to board %s: %w", b.BoardName, err) - } else { - if s, err := board.IsUserPasswordSet(conn); err != nil { - return fmt.Errorf("failed to check if user password is set: %w", err) - } else { - configured = "- Configured: " + strconv.FormatBool(s) - } - } - case board.NetworkProtocol: - address = b.Address - default: - panic("unreachable") - } - - feedback.Printf("%s (%s) - Connection: %s [%s] %s\n", b.BoardName, b.CustomName, b.Protocol, address, configured) - } - return nil - }, - } - - return listCmd -} - -func newBoardSetName() *cobra.Command { - setNameCmd := &cobra.Command{ - Use: "set-name ", - Short: "Set the custom name of the board", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - conn := cmd.Context().Value(remoteConnKey).(remote.RemoteConn) - name := args[0] - - if err := board.SetCustomName(cmd.Context(), conn, name); err != nil { - return fmt.Errorf("failed to set custom name: %w", err) - } - feedback.Printf("Custom name set to %q\n", name) - return nil - }, - } - - return setNameCmd -} - -func newSetPasswordCmd() *cobra.Command { - return &cobra.Command{ - Use: "set-password", - Short: "Set the user password of the board", - Args: cobra.ExactArgs(0), - RunE: func(cmd *cobra.Command, args []string) error { - conn := cmd.Context().Value(remoteConnKey).(remote.RemoteConn) - - feedback.Print("Enter new password: ") - // TODO: fix for not interactive terminal - password, err := term.ReadPassword(int(os.Stdin.Fd())) // nolint:forbidigo - if err != nil { - return fmt.Errorf("failed to read password: %w", err) - } - - if err := board.SetUserPassword(cmd.Context(), conn, string(password)); err != nil { - return fmt.Errorf("failed to set user password: %w", err) - } - - feedback.Printf("User password set\n") - return nil - }, - } -} - -func newEnableNetworkModeCmd() *cobra.Command { - return &cobra.Command{ - Use: "enable-ssh", - Short: "Enable and start the SSH service on the board", - Args: cobra.ExactArgs(0), - RunE: func(cmd *cobra.Command, args []string) error { - conn := cmd.Context().Value(remoteConnKey).(remote.RemoteConn) - - if err := board.EnableNetworkMode(cmd.Context(), conn); err != nil { - return fmt.Errorf("failed to enable SSH: %w", err) - } - - feedback.Printf("SSH service enabled and started\n") - return nil - }, - } -} - -func newDisableNetworkModeCmd() *cobra.Command { - return &cobra.Command{ - Use: "disable-ssh", - Short: "Disable and stop the SSH service on the board", - Args: cobra.ExactArgs(0), - RunE: func(cmd *cobra.Command, args []string) error { - conn := cmd.Context().Value(remoteConnKey).(remote.RemoteConn) - - if err := board.DisableNetworkMode(cmd.Context(), conn); err != nil { - return fmt.Errorf("failed to disable SSH: %w", err) - } - - feedback.Printf("SSH service disabled and stopped\n") - return nil - }, - } -} - -func newNetworkModeStatusCmd() *cobra.Command { - return &cobra.Command{ - Use: "status-ssh", - Short: "Check the status of the network mode on the board", - Args: cobra.ExactArgs(0), - RunE: func(cmd *cobra.Command, args []string) error { - conn := cmd.Context().Value(remoteConnKey).(remote.RemoteConn) - - isEnabled, err := board.NetworkModeStatus(cmd.Context(), conn) - if err != nil { - return fmt.Errorf("failed to check network mode status: %w", err) - } - - feedback.Printf("Network mode is %s\n", map[bool]string{true: "enabled", false: "disabled"}[isEnabled]) - return nil - }, - } -} - -func getKeyboardLayout() *cobra.Command { - return &cobra.Command{ - Use: "get-keyboard-layout", - Short: "Returns the current system keyboard layout code", - Args: cobra.ExactArgs(0), - RunE: func(cmd *cobra.Command, args []string) error { - conn := cmd.Context().Value(remoteConnKey).(remote.RemoteConn) - - layoutCode, err := board.GetKeyboardLayout(cmd.Context(), conn) - if err != nil { - return fmt.Errorf("failed: %w", err) - } - feedback.Printf("Layout: %s", layoutCode) - - return nil - }, - } -} - -func setKeyboardLayout() *cobra.Command { - return &cobra.Command{ - Use: "set-keyboard-layout ", - Short: "Saves and applies the current system keyboard layout", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - conn := cmd.Context().Value(remoteConnKey).(remote.RemoteConn) - layoutCode := args[0] - - err := validateKeyboardLayoutCode(conn, layoutCode) - if err != nil { - return fmt.Errorf("failed: %w", err) - } - - err = board.SetKeyboardLayout(cmd.Context(), conn, layoutCode) - if err != nil { - return fmt.Errorf("failed: %w", err) - } - - feedback.Printf("New layout applied: %s", layoutCode) - return nil - }, - } -} - -func validateKeyboardLayoutCode(conn remote.RemoteConn, layoutCode string) error { - // Make sure the input layout code is in the list of valid ones - layouts, err := board.ListKeyboardLayouts(conn) - if err != nil { - return fmt.Errorf("failed to fetch valid layouts: %w", err) - } - - for _, layout := range layouts { - if layout.LayoutId == layoutCode { - return nil - } - } - - return fmt.Errorf("invalid layout code: %s", layoutCode) -} - -func listKeyboardLayouts() *cobra.Command { - return &cobra.Command{ - Use: "list-keyboard-layouts", - Short: "Returns the list of valid keyboard layouts, with a description", - Args: cobra.ExactArgs(0), - RunE: func(cmd *cobra.Command, args []string) error { - conn := cmd.Context().Value(remoteConnKey).(remote.RemoteConn) - - layouts, err := board.ListKeyboardLayouts(conn) - if err != nil { - return fmt.Errorf("failed: %w", err) - } - - for _, layout := range layouts { - feedback.Printf("%s, %s", layout.LayoutId, layout.Description) - } - - return nil - }, - } -} diff --git a/cmd/arduino-app-cli/main.go b/cmd/arduino-app-cli/main.go index 4df37ca8..765ccd69 100644 --- a/cmd/arduino-app-cli/main.go +++ b/cmd/arduino-app-cli/main.go @@ -25,7 +25,6 @@ import ( "go.bug.st/cleanup" "github.com/arduino/arduino-app-cli/cmd/arduino-app-cli/app" - "github.com/arduino/arduino-app-cli/cmd/arduino-app-cli/board" "github.com/arduino/arduino-app-cli/cmd/arduino-app-cli/brick" "github.com/arduino/arduino-app-cli/cmd/arduino-app-cli/completion" "github.com/arduino/arduino-app-cli/cmd/arduino-app-cli/config" @@ -78,7 +77,6 @@ func run(configuration cfg.Configuration) error { properties.NewPropertiesCmd(configuration), config.NewConfigCmd(configuration), system.NewSystemCmd(configuration), - board.NewBoardCmd(), version.NewVersionCmd(Version), ) diff --git a/cmd/arduino-app-cli/system/system.go b/cmd/arduino-app-cli/system/system.go index 6297797f..dd9986de 100644 --- a/cmd/arduino-app-cli/system/system.go +++ b/cmd/arduino-app-cli/system/system.go @@ -40,16 +40,17 @@ func NewSystemCmd(cfg config.Configuration) *cobra.Command { Use: "system", } - cmd.AddCommand(newDownloadImage(cfg)) + cmd.AddCommand(newDownloadImageCmd(cfg)) cmd.AddCommand(newUpdateCmd()) cmd.AddCommand(newCleanUpCmd(cfg, servicelocator.GetDockerClient())) - cmd.AddCommand(newNetworkMode()) - cmd.AddCommand(newkeyboardSet()) + cmd.AddCommand(newNetworkModeCmd()) + cmd.AddCommand(newKeyboardSetCmd()) + cmd.AddCommand(newBoardSetNameCmd()) return cmd } -func newDownloadImage(cfg config.Configuration) *cobra.Command { +func newDownloadImageCmd(cfg config.Configuration) *cobra.Command { cmd := &cobra.Command{ Use: "init", Args: cobra.ExactArgs(0), @@ -173,7 +174,7 @@ func newCleanUpCmd(cfg config.Configuration, docker command.Cli) *cobra.Command return cmd } -func newNetworkMode() *cobra.Command { +func newNetworkModeCmd() *cobra.Command { cmd := &cobra.Command{ Use: "network-mode ", Short: "Manage the network mode of the system", @@ -209,7 +210,7 @@ func newNetworkMode() *cobra.Command { return cmd } -func newkeyboardSet() *cobra.Command { +func newKeyboardSetCmd() *cobra.Command { cmd := &cobra.Command{ Use: "keyboard [layout]", Short: "Manage the keyboard layout of the system", @@ -250,3 +251,21 @@ func newkeyboardSet() *cobra.Command { return cmd } + +func newBoardSetNameCmd() *cobra.Command { + setNameCmd := &cobra.Command{ + Use: "set-name ", + Short: "Set the custom name of the board", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + name := args[0] + if err := board.SetCustomName(cmd.Context(), &local.LocalConnection{}, name); err != nil { + return fmt.Errorf("failed to set custom name: %w", err) + } + feedback.Printf("Custom name set to %q\n", name) + return nil + }, + } + + return setNameCmd +} diff --git a/go.mod b/go.mod index 48ac9537..be40aceb 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,6 @@ require ( go.bug.st/relaxed-semver v0.15.0 golang.org/x/crypto v0.41.0 golang.org/x/sync v0.17.0 - golang.org/x/term v0.35.0 golang.org/x/text v0.29.0 ) @@ -291,6 +290,7 @@ require ( golang.org/x/net v0.43.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sys v0.36.0 // indirect + golang.org/x/term v0.35.0 // indirect golang.org/x/time v0.11.0 // indirect golang.org/x/tools v0.36.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect