From ccef5a119c79e9f4f4a748815b4ecd73d0ca500f Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 27 Nov 2024 18:06:20 +0100 Subject: [PATCH 1/6] Made FQBN parsing package public Because it may turn out useful for other projects. --- commands/service_board_details.go | 6 +- commands/service_board_list.go | 12 +-- commands/service_compile.go | 6 +- commands/service_debug_config.go | 6 +- commands/service_library_list.go | 10 +- commands/service_monitor.go | 7 +- commands/service_upload.go | 9 +- commands/service_upload_list_programmers.go | 3 +- commands/service_upload_test.go | 5 +- .../arduino/builder/build_options_manager.go | 4 +- internal/arduino/builder/builder.go | 3 +- internal/arduino/cores/board.go | 5 +- .../cores/packagemanager/package_manager.go | 23 ++--- .../packagemanager/package_manager_test.go | 53 +++++------ internal/cli/board/list.go | 10 +- {internal/arduino/cores => pkg/fqbn}/fqbn.go | 63 +++++++------ .../arduino/cores => pkg/fqbn}/fqbn_test.go | 91 ++++++++++--------- 17 files changed, 162 insertions(+), 154 deletions(-) rename {internal/arduino/cores => pkg/fqbn}/fqbn.go (80%) rename {internal/arduino/cores => pkg/fqbn}/fqbn_test.go (71%) diff --git a/commands/service_board_details.go b/commands/service_board_details.go index 5f042452582..4104c9bc21b 100644 --- a/commands/service_board_details.go +++ b/commands/service_board_details.go @@ -20,8 +20,8 @@ import ( "github.com/arduino/arduino-cli/commands/cmderrors" "github.com/arduino/arduino-cli/commands/internal/instances" - "github.com/arduino/arduino-cli/internal/arduino/cores" "github.com/arduino/arduino-cli/internal/arduino/utils" + "github.com/arduino/arduino-cli/pkg/fqbn" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" ) @@ -34,7 +34,7 @@ func (s *arduinoCoreServerImpl) BoardDetails(ctx context.Context, req *rpc.Board } defer release() - fqbn, err := cores.ParseFQBN(req.GetFqbn()) + fqbn, err := fqbn.Parse(req.GetFqbn()) if err != nil { return nil, &cmderrors.InvalidFQBNError{Cause: err} } @@ -48,7 +48,7 @@ func (s *arduinoCoreServerImpl) BoardDetails(ctx context.Context, req *rpc.Board details.Name = board.Name() details.Fqbn = board.FQBN() details.PropertiesId = board.BoardID - details.Official = fqbn.Package == "arduino" + details.Official = fqbn.Packager == "arduino" details.Version = board.PlatformRelease.Version.String() details.IdentificationProperties = []*rpc.BoardIdentificationProperties{} for _, p := range board.GetIdentificationProperties() { diff --git a/commands/service_board_list.go b/commands/service_board_list.go index 2b124c29f37..9a84e3319f5 100644 --- a/commands/service_board_list.go +++ b/commands/service_board_list.go @@ -30,11 +30,11 @@ import ( "github.com/arduino/arduino-cli/commands/cmderrors" "github.com/arduino/arduino-cli/commands/internal/instances" f "github.com/arduino/arduino-cli/internal/algorithms" - "github.com/arduino/arduino-cli/internal/arduino/cores" "github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager" "github.com/arduino/arduino-cli/internal/cli/configuration" "github.com/arduino/arduino-cli/internal/i18n" "github.com/arduino/arduino-cli/internal/inventory" + "github.com/arduino/arduino-cli/pkg/fqbn" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-properties-orderedmap" discovery "github.com/arduino/pluggable-discovery-protocol-handler/v2" @@ -148,7 +148,7 @@ func identify(pme *packagemanager.Explorer, port *discovery.Port, settings *conf // first query installed cores through the Package Manager logrus.Debug("Querying installed cores for board identification...") for _, board := range pme.IdentifyBoard(port.Properties) { - fqbn, err := cores.ParseFQBN(board.FQBN()) + fqbn, err := fqbn.Parse(board.FQBN()) if err != nil { return nil, &cmderrors.InvalidFQBNError{Cause: err} } @@ -210,10 +210,10 @@ func (s *arduinoCoreServerImpl) BoardList(ctx context.Context, req *rpc.BoardLis } defer release() - var fqbnFilter *cores.FQBN + var fqbnFilter *fqbn.FQBN if f := req.GetFqbn(); f != "" { var err error - fqbnFilter, err = cores.ParseFQBN(f) + fqbnFilter, err = fqbn.Parse(f) if err != nil { return nil, &cmderrors.InvalidFQBNError{Cause: err} } @@ -247,9 +247,9 @@ func (s *arduinoCoreServerImpl) BoardList(ctx context.Context, req *rpc.BoardLis }, nil } -func hasMatchingBoard(b *rpc.DetectedPort, fqbnFilter *cores.FQBN) bool { +func hasMatchingBoard(b *rpc.DetectedPort, fqbnFilter *fqbn.FQBN) bool { for _, detectedBoard := range b.GetMatchingBoards() { - detectedFqbn, err := cores.ParseFQBN(detectedBoard.GetFqbn()) + detectedFqbn, err := fqbn.Parse(detectedBoard.GetFqbn()) if err != nil { continue } diff --git a/commands/service_compile.go b/commands/service_compile.go index a7ce1ea2bbf..61f8e1ef1d7 100644 --- a/commands/service_compile.go +++ b/commands/service_compile.go @@ -28,13 +28,13 @@ import ( "github.com/arduino/arduino-cli/commands/cmderrors" "github.com/arduino/arduino-cli/commands/internal/instances" "github.com/arduino/arduino-cli/internal/arduino/builder" - "github.com/arduino/arduino-cli/internal/arduino/cores" "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesmanager" "github.com/arduino/arduino-cli/internal/arduino/sketch" "github.com/arduino/arduino-cli/internal/arduino/utils" "github.com/arduino/arduino-cli/internal/buildcache" "github.com/arduino/arduino-cli/internal/i18n" "github.com/arduino/arduino-cli/internal/inventory" + "github.com/arduino/arduino-cli/pkg/fqbn" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" "github.com/sirupsen/logrus" @@ -116,7 +116,7 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu return &cmderrors.MissingFQBNError{} } - fqbn, err := cores.ParseFQBN(fqbnIn) + fqbn, err := fqbn.Parse(fqbnIn) if err != nil { return &cmderrors.InvalidFQBNError{Cause: err} } @@ -124,7 +124,7 @@ func (s *arduinoCoreServerImpl) Compile(req *rpc.CompileRequest, stream rpc.Ardu if err != nil { if targetPlatform == nil { return &cmderrors.PlatformNotFoundError{ - Platform: fmt.Sprintf("%s:%s", fqbn.Package, fqbn.PlatformArch), + Platform: fmt.Sprintf("%s:%s", fqbn.Packager, fqbn.Architecture), Cause: errors.New(i18n.Tr("platform not installed")), } } diff --git a/commands/service_debug_config.go b/commands/service_debug_config.go index c2cf04e5aa3..f755b68adb5 100644 --- a/commands/service_debug_config.go +++ b/commands/service_debug_config.go @@ -27,10 +27,10 @@ import ( "github.com/arduino/arduino-cli/commands/cmderrors" "github.com/arduino/arduino-cli/commands/internal/instances" - "github.com/arduino/arduino-cli/internal/arduino/cores" "github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager" "github.com/arduino/arduino-cli/internal/arduino/sketch" "github.com/arduino/arduino-cli/internal/i18n" + "github.com/arduino/arduino-cli/pkg/fqbn" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" @@ -76,7 +76,7 @@ func (s *arduinoCoreServerImpl) IsDebugSupported(ctx context.Context, req *rpc.I // Compute the minimum FQBN required to get the same debug configuration. // (i.e. the FQBN cleaned up of the options that do not affect the debugger configuration) - minimumFQBN := cores.MustParseFQBN(req.GetFqbn()) + minimumFQBN := fqbn.MustParse(req.GetFqbn()) for _, config := range minimumFQBN.Configs.Keys() { checkFQBN := minimumFQBN.Clone() checkFQBN.Configs.Remove(config) @@ -127,7 +127,7 @@ func (s *arduinoCoreServerImpl) getDebugProperties(req *rpc.GetDebugConfigReques if fqbnIn == "" { return nil, &cmderrors.MissingFQBNError{} } - fqbn, err := cores.ParseFQBN(fqbnIn) + fqbn, err := fqbn.Parse(fqbnIn) if err != nil { return nil, &cmderrors.InvalidFQBNError{Cause: err} } diff --git a/commands/service_library_list.go b/commands/service_library_list.go index 35104caf08b..2d30e11dbd3 100644 --- a/commands/service_library_list.go +++ b/commands/service_library_list.go @@ -21,12 +21,12 @@ import ( "github.com/arduino/arduino-cli/commands/cmderrors" "github.com/arduino/arduino-cli/commands/internal/instances" - "github.com/arduino/arduino-cli/internal/arduino/cores" "github.com/arduino/arduino-cli/internal/arduino/libraries" "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesindex" "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesmanager" "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesresolver" "github.com/arduino/arduino-cli/internal/i18n" + "github.com/arduino/arduino-cli/pkg/fqbn" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" ) @@ -59,7 +59,7 @@ func (s *arduinoCoreServerImpl) LibraryList(ctx context.Context, req *rpc.Librar var allLibs []*installedLib if fqbnString := req.GetFqbn(); fqbnString != "" { allLibs = listLibraries(lme, li, req.GetUpdatable(), true) - fqbn, err := cores.ParseFQBN(req.GetFqbn()) + fqbn, err := fqbn.Parse(req.GetFqbn()) if err != nil { return nil, &cmderrors.InvalidFQBNError{Cause: err} } @@ -77,8 +77,8 @@ func (s *arduinoCoreServerImpl) LibraryList(ctx context.Context, req *rpc.Librar } } if latest, has := filteredRes[lib.Library.Name]; has { - latestPriority := librariesresolver.ComputePriority(latest.Library, "", fqbn.PlatformArch) - libPriority := librariesresolver.ComputePriority(lib.Library, "", fqbn.PlatformArch) + latestPriority := librariesresolver.ComputePriority(latest.Library, "", fqbn.Architecture) + libPriority := librariesresolver.ComputePriority(lib.Library, "", fqbn.Architecture) if latestPriority >= libPriority { // Pick library with the best priority continue @@ -87,7 +87,7 @@ func (s *arduinoCoreServerImpl) LibraryList(ctx context.Context, req *rpc.Librar // Check if library is compatible with board specified by FBQN lib.Library.CompatibleWith = map[string]bool{ - fqbnString: lib.Library.IsCompatibleWith(fqbn.PlatformArch), + fqbnString: lib.Library.IsCompatibleWith(fqbn.Architecture), } filteredRes[lib.Library.Name] = lib diff --git a/commands/service_monitor.go b/commands/service_monitor.go index 8c3402681b7..012d4ddf8bc 100644 --- a/commands/service_monitor.go +++ b/commands/service_monitor.go @@ -28,6 +28,7 @@ import ( "github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager" pluggableMonitor "github.com/arduino/arduino-cli/internal/arduino/monitor" "github.com/arduino/arduino-cli/internal/i18n" + "github.com/arduino/arduino-cli/pkg/fqbn" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-properties-orderedmap" "github.com/djherbis/buffer" @@ -237,7 +238,7 @@ func (s *arduinoCoreServerImpl) Monitor(stream rpc.ArduinoCoreService_MonitorSer return nil } -func findMonitorAndSettingsForProtocolAndBoard(pme *packagemanager.Explorer, protocol, fqbn string) (*pluggableMonitor.PluggableMonitor, *properties.Map, error) { +func findMonitorAndSettingsForProtocolAndBoard(pme *packagemanager.Explorer, protocol, fqbnIn string) (*pluggableMonitor.PluggableMonitor, *properties.Map, error) { if protocol == "" { return nil, nil, &cmderrors.MissingPortProtocolError{} } @@ -246,8 +247,8 @@ func findMonitorAndSettingsForProtocolAndBoard(pme *packagemanager.Explorer, pro boardSettings := properties.NewMap() // If a board is specified search the monitor in the board package first - if fqbn != "" { - fqbn, err := cores.ParseFQBN(fqbn) + if fqbnIn != "" { + fqbn, err := fqbn.Parse(fqbnIn) if err != nil { return nil, nil, &cmderrors.InvalidFQBNError{Cause: err} } diff --git a/commands/service_upload.go b/commands/service_upload.go index 56d621813fe..2e5e9272d51 100644 --- a/commands/service_upload.go +++ b/commands/service_upload.go @@ -32,6 +32,7 @@ import ( "github.com/arduino/arduino-cli/internal/arduino/globals" "github.com/arduino/arduino-cli/internal/arduino/sketch" "github.com/arduino/arduino-cli/internal/i18n" + "github.com/arduino/arduino-cli/pkg/fqbn" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" properties "github.com/arduino/go-properties-orderedmap" @@ -53,7 +54,7 @@ func (s *arduinoCoreServerImpl) SupportedUserFields(ctx context.Context, req *rp } defer release() - fqbn, err := cores.ParseFQBN(req.GetFqbn()) + fqbn, err := fqbn.Parse(req.GetFqbn()) if err != nil { return nil, &cmderrors.InvalidFQBNError{Cause: err} } @@ -61,7 +62,7 @@ func (s *arduinoCoreServerImpl) SupportedUserFields(ctx context.Context, req *rp _, platformRelease, _, boardProperties, _, err := pme.ResolveFQBN(fqbn) if platformRelease == nil { return nil, &cmderrors.PlatformNotFoundError{ - Platform: fmt.Sprintf("%s:%s", fqbn.Package, fqbn.PlatformArch), + Platform: fmt.Sprintf("%s:%s", fqbn.Packager, fqbn.Architecture), Cause: err, } } else if err != nil { @@ -282,7 +283,7 @@ func (s *arduinoCoreServerImpl) runProgramAction(ctx context.Context, pme *packa return nil, &cmderrors.MissingProgrammerError{} } - fqbn, err := cores.ParseFQBN(fqbnIn) + fqbn, err := fqbn.Parse(fqbnIn) if err != nil { return nil, &cmderrors.InvalidFQBNError{Cause: err} } @@ -292,7 +293,7 @@ func (s *arduinoCoreServerImpl) runProgramAction(ctx context.Context, pme *packa _, boardPlatform, board, boardProperties, buildPlatform, err := pme.ResolveFQBN(fqbn) if boardPlatform == nil { return nil, &cmderrors.PlatformNotFoundError{ - Platform: fmt.Sprintf("%s:%s", fqbn.Package, fqbn.PlatformArch), + Platform: fmt.Sprintf("%s:%s", fqbn.Packager, fqbn.Architecture), Cause: err, } } else if err != nil { diff --git a/commands/service_upload_list_programmers.go b/commands/service_upload_list_programmers.go index f05142cf147..761d9babf5c 100644 --- a/commands/service_upload_list_programmers.go +++ b/commands/service_upload_list_programmers.go @@ -21,6 +21,7 @@ import ( "github.com/arduino/arduino-cli/commands/cmderrors" "github.com/arduino/arduino-cli/commands/internal/instances" "github.com/arduino/arduino-cli/internal/arduino/cores" + "github.com/arduino/arduino-cli/pkg/fqbn" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" ) @@ -36,7 +37,7 @@ func (s *arduinoCoreServerImpl) ListProgrammersAvailableForUpload(ctx context.Co if fqbnIn == "" { return nil, &cmderrors.MissingFQBNError{} } - fqbn, err := cores.ParseFQBN(fqbnIn) + fqbn, err := fqbn.Parse(fqbnIn) if err != nil { return nil, &cmderrors.InvalidFQBNError{Cause: err} } diff --git a/commands/service_upload_test.go b/commands/service_upload_test.go index 737eec92e83..4a86a0f274b 100644 --- a/commands/service_upload_test.go +++ b/commands/service_upload_test.go @@ -25,6 +25,7 @@ import ( "github.com/arduino/arduino-cli/internal/arduino/cores" "github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager" "github.com/arduino/arduino-cli/internal/arduino/sketch" + "github.com/arduino/arduino-cli/pkg/fqbn" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" properties "github.com/arduino/go-properties-orderedmap" @@ -60,7 +61,7 @@ func TestDetermineBuildPathAndSketchName(t *testing.T) { importFile string importDir string sketch *sketch.Sketch - fqbn *cores.FQBN + fqbn *fqbn.FQBN resBuildPath string resSketchName string } @@ -68,7 +69,7 @@ func TestDetermineBuildPathAndSketchName(t *testing.T) { blonk, err := sketch.New(paths.New("testdata/upload/Blonk")) require.NoError(t, err) - fqbn, err := cores.ParseFQBN("arduino:samd:mkr1000") + fqbn, err := fqbn.Parse("arduino:samd:mkr1000") require.NoError(t, err) srv := NewArduinoCoreServer().(*arduinoCoreServerImpl) diff --git a/internal/arduino/builder/build_options_manager.go b/internal/arduino/builder/build_options_manager.go index 09f0afad815..ebaf97bda28 100644 --- a/internal/arduino/builder/build_options_manager.go +++ b/internal/arduino/builder/build_options_manager.go @@ -22,9 +22,9 @@ import ( "strings" "github.com/arduino/arduino-cli/internal/arduino/builder/internal/utils" - "github.com/arduino/arduino-cli/internal/arduino/cores" "github.com/arduino/arduino-cli/internal/arduino/sketch" "github.com/arduino/arduino-cli/internal/i18n" + "github.com/arduino/arduino-cli/pkg/fqbn" "github.com/arduino/go-paths-helper" properties "github.com/arduino/go-properties-orderedmap" ) @@ -51,7 +51,7 @@ func newBuildOptions( builtInLibrariesDirs, buildPath *paths.Path, sketch *sketch.Sketch, customBuildProperties []string, - fqbn *cores.FQBN, + fqbn *fqbn.FQBN, clean bool, compilerOptimizationFlags string, runtimePlatformPath, buildCorePath *paths.Path, diff --git a/internal/arduino/builder/builder.go b/internal/arduino/builder/builder.go index 91c74965782..58d607c827a 100644 --- a/internal/arduino/builder/builder.go +++ b/internal/arduino/builder/builder.go @@ -35,6 +35,7 @@ import ( "github.com/arduino/arduino-cli/internal/arduino/libraries/librariesmanager" "github.com/arduino/arduino-cli/internal/arduino/sketch" "github.com/arduino/arduino-cli/internal/i18n" + "github.com/arduino/arduino-cli/pkg/fqbn" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" @@ -127,7 +128,7 @@ func NewBuilder( requestBuildProperties []string, hardwareDirs, otherLibrariesDirs paths.PathList, builtInLibrariesDirs *paths.Path, - fqbn *cores.FQBN, + fqbn *fqbn.FQBN, clean bool, sourceOverrides map[string]string, onlyUpdateCompilationDatabase bool, diff --git a/internal/arduino/cores/board.go b/internal/arduino/cores/board.go index ed1aa9c68b5..6e966a68aee 100644 --- a/internal/arduino/cores/board.go +++ b/internal/arduino/cores/board.go @@ -21,6 +21,7 @@ import ( "sync" "github.com/arduino/arduino-cli/internal/i18n" + "github.com/arduino/arduino-cli/pkg/fqbn" "github.com/arduino/go-properties-orderedmap" ) @@ -124,7 +125,7 @@ func (b *Board) GetConfigOptionValues(option string) *properties.Map { // GetBuildProperties returns the build properties and the build // platform for the Board with the configuration passed as parameter. -func (b *Board) GetBuildProperties(fqbn *FQBN) (*properties.Map, error) { +func (b *Board) GetBuildProperties(fqbn *fqbn.FQBN) (*properties.Map, error) { b.buildConfigOptionsStructures() // Override default configs with user configs @@ -161,7 +162,7 @@ func (b *Board) GetBuildProperties(fqbn *FQBN) (*properties.Map, error) { // "cpu=atmega2560". // FIXME: deprecated, use GetBuildProperties instead func (b *Board) GeneratePropertiesForConfiguration(config string) (*properties.Map, error) { - fqbn, err := ParseFQBN(b.String() + ":" + config) + fqbn, err := fqbn.Parse(b.String() + ":" + config) if err != nil { return nil, errors.New(i18n.Tr("parsing fqbn: %s", err)) } diff --git a/internal/arduino/cores/packagemanager/package_manager.go b/internal/arduino/cores/packagemanager/package_manager.go index aaaf675a410..4c22c19c6e4 100644 --- a/internal/arduino/cores/packagemanager/package_manager.go +++ b/internal/arduino/cores/packagemanager/package_manager.go @@ -33,6 +33,7 @@ import ( "github.com/arduino/arduino-cli/internal/arduino/discovery/discoverymanager" "github.com/arduino/arduino-cli/internal/arduino/sketch" "github.com/arduino/arduino-cli/internal/i18n" + "github.com/arduino/arduino-cli/pkg/fqbn" paths "github.com/arduino/go-paths-helper" properties "github.com/arduino/go-properties-orderedmap" "github.com/arduino/go-timeutils" @@ -290,7 +291,7 @@ func (pme *Explorer) FindBoardsWithID(id string) []*cores.Board { // FindBoardWithFQBN returns the board identified by the fqbn, or an error func (pme *Explorer) FindBoardWithFQBN(fqbnIn string) (*cores.Board, error) { - fqbn, err := cores.ParseFQBN(fqbnIn) + fqbn, err := fqbn.Parse(fqbnIn) if err != nil { return nil, errors.New(i18n.Tr("parsing fqbn: %s", err)) } @@ -318,22 +319,22 @@ func (pme *Explorer) FindBoardWithFQBN(fqbnIn string) (*cores.Board, error) { // // In case of error the partial results found in the meantime are // returned together with the error. -func (pme *Explorer) ResolveFQBN(fqbn *cores.FQBN) ( +func (pme *Explorer) ResolveFQBN(fqbn *fqbn.FQBN) ( *cores.Package, *cores.PlatformRelease, *cores.Board, *properties.Map, *cores.PlatformRelease, error) { // Find package - targetPackage := pme.packages[fqbn.Package] + targetPackage := pme.packages[fqbn.Packager] if targetPackage == nil { return nil, nil, nil, nil, nil, - errors.New(i18n.Tr("unknown package %s", fqbn.Package)) + errors.New(i18n.Tr("unknown package %s", fqbn.Packager)) } // Find platform - platform := targetPackage.Platforms[fqbn.PlatformArch] + platform := targetPackage.Platforms[fqbn.Architecture] if platform == nil { return targetPackage, nil, nil, nil, nil, - errors.New(i18n.Tr("unknown platform %s:%s", targetPackage, fqbn.PlatformArch)) + errors.New(i18n.Tr("unknown platform %s:%s", targetPackage, fqbn.Architecture)) } boardPlatformRelease := pme.GetInstalledPlatformRelease(platform) if boardPlatformRelease == nil { @@ -429,7 +430,7 @@ func (pme *Explorer) ResolveFQBN(fqbn *cores.FQBN) ( return targetPackage, boardPlatformRelease, board, buildProperties, corePlatformRelease, nil } -func (pme *Explorer) determineReferencedPlatformRelease(boardBuildProperties *properties.Map, boardPlatformRelease *cores.PlatformRelease, fqbn *cores.FQBN) (string, *cores.PlatformRelease, string, *cores.PlatformRelease, error) { +func (pme *Explorer) determineReferencedPlatformRelease(boardBuildProperties *properties.Map, boardPlatformRelease *cores.PlatformRelease, fqbn *fqbn.FQBN) (string, *cores.PlatformRelease, string, *cores.PlatformRelease, error) { core := boardBuildProperties.ExpandPropsInString(boardBuildProperties.Get("build.core")) referredCore := "" if split := strings.Split(core, ":"); len(split) > 1 { @@ -461,15 +462,15 @@ func (pme *Explorer) determineReferencedPlatformRelease(boardBuildProperties *pr return "", nil, "", nil, errors.New(i18n.Tr("missing package %[1]s referenced by board %[2]s", referredPackageName, fqbn)) } - referredPlatform := referredPackage.Platforms[fqbn.PlatformArch] + referredPlatform := referredPackage.Platforms[fqbn.Architecture] if referredPlatform == nil { return "", nil, "", nil, - errors.New(i18n.Tr("missing platform %[1]s:%[2]s referenced by board %[3]s", referredPackageName, fqbn.PlatformArch, fqbn)) + errors.New(i18n.Tr("missing platform %[1]s:%[2]s referenced by board %[3]s", referredPackageName, fqbn.Architecture, fqbn)) } referredPlatformRelease = pme.GetInstalledPlatformRelease(referredPlatform) if referredPlatformRelease == nil { return "", nil, "", nil, - errors.New(i18n.Tr("missing platform release %[1]s:%[2]s referenced by board %[3]s", referredPackageName, fqbn.PlatformArch, fqbn)) + errors.New(i18n.Tr("missing platform release %[1]s:%[2]s referenced by board %[3]s", referredPackageName, fqbn.Architecture, fqbn)) } } @@ -890,7 +891,7 @@ func (pme *Explorer) FindMonitorDependency(discovery *cores.MonitorDependency) * // NormalizeFQBN return a normalized copy of the given FQBN, that is the same // FQBN but with the unneeded or invalid options removed. -func (pme *Explorer) NormalizeFQBN(fqbn *cores.FQBN) (*cores.FQBN, error) { +func (pme *Explorer) NormalizeFQBN(fqbn *fqbn.FQBN) (*fqbn.FQBN, error) { _, _, board, _, _, err := pme.ResolveFQBN(fqbn) if err != nil { return nil, err diff --git a/internal/arduino/cores/packagemanager/package_manager_test.go b/internal/arduino/cores/packagemanager/package_manager_test.go index 4f8598a515a..92530af6dc3 100644 --- a/internal/arduino/cores/packagemanager/package_manager_test.go +++ b/internal/arduino/cores/packagemanager/package_manager_test.go @@ -24,6 +24,7 @@ import ( "testing" "github.com/arduino/arduino-cli/internal/arduino/cores" + "github.com/arduino/arduino-cli/pkg/fqbn" "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" "github.com/stretchr/testify/require" @@ -69,7 +70,7 @@ func TestResolveFQBN(t *testing.T) { t.Run("NormalizeFQBN", func(t *testing.T) { testNormalization := func(in, expected string) { - fqbn, err := cores.ParseFQBN(in) + fqbn, err := fqbn.Parse(in) require.Nil(t, err) require.NotNil(t, fqbn) normalized, err := pme.NormalizeFQBN(fqbn) @@ -92,7 +93,7 @@ func TestResolveFQBN(t *testing.T) { }) t.Run("BoardAndBuildPropertiesArduinoUno", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("arduino:avr:uno") + fqbn, err := fqbn.Parse("arduino:avr:uno") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -113,7 +114,7 @@ func TestResolveFQBN(t *testing.T) { }) t.Run("BoardAndBuildPropertiesArduinoMega", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("arduino:avr:mega") + fqbn, err := fqbn.Parse("arduino:avr:mega") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -129,7 +130,7 @@ func TestResolveFQBN(t *testing.T) { }) t.Run("BoardAndBuildPropertiesArduinoMegaWithNonDefaultCpuOption", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("arduino:avr:mega:cpu=atmega1280") + fqbn, err := fqbn.Parse("arduino:avr:mega:cpu=atmega1280") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -147,7 +148,7 @@ func TestResolveFQBN(t *testing.T) { }) t.Run("BoardAndBuildPropertiesArduinoMegaWithDefaultCpuOption", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("arduino:avr:mega:cpu=atmega2560") + fqbn, err := fqbn.Parse("arduino:avr:mega:cpu=atmega2560") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -167,7 +168,7 @@ func TestResolveFQBN(t *testing.T) { t.Run("BoardAndBuildPropertiesForReferencedArduinoUno", func(t *testing.T) { // Test a board referenced from the main AVR arduino platform - fqbn, err := cores.ParseFQBN("referenced:avr:uno") + fqbn, err := fqbn.Parse("referenced:avr:uno") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -185,7 +186,7 @@ func TestResolveFQBN(t *testing.T) { }) t.Run("BoardAndBuildPropertiesForArduinoDue", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("arduino:sam:arduino_due_x") + fqbn, err := fqbn.Parse("arduino:sam:arduino_due_x") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -200,7 +201,7 @@ func TestResolveFQBN(t *testing.T) { }) t.Run("BoardAndBuildPropertiesForCustomArduinoYun", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("my_avr_platform:avr:custom_yun") + fqbn, err := fqbn.Parse("my_avr_platform:avr:custom_yun") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -216,7 +217,7 @@ func TestResolveFQBN(t *testing.T) { }) t.Run("BoardAndBuildPropertiesForWatterotCore", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("watterott:avr:attiny841:core=spencekonde,info=info") + fqbn, err := fqbn.Parse("watterott:avr:attiny841:core=spencekonde,info=info") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -234,7 +235,7 @@ func TestResolveFQBN(t *testing.T) { t.Run("BoardAndBuildPropertiesForReferencedFeatherM0", func(t *testing.T) { // Test a board referenced from the Adafruit SAMD core (this tests // deriving where the package and core name are different) - fqbn, err := cores.ParseFQBN("referenced:samd:feather_m0") + fqbn, err := fqbn.Parse("referenced:samd:feather_m0") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -253,7 +254,7 @@ func TestResolveFQBN(t *testing.T) { t.Run("BoardAndBuildPropertiesForNonExistentPackage", func(t *testing.T) { // Test a board referenced from a non-existent package - fqbn, err := cores.ParseFQBN("referenced:avr:dummy_invalid_package") + fqbn, err := fqbn.Parse("referenced:avr:dummy_invalid_package") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -270,7 +271,7 @@ func TestResolveFQBN(t *testing.T) { t.Run("BoardAndBuildPropertiesForNonExistentArchitecture", func(t *testing.T) { // Test a board referenced from a non-existent platform/architecture - fqbn, err := cores.ParseFQBN("referenced:avr:dummy_invalid_platform") + fqbn, err := fqbn.Parse("referenced:avr:dummy_invalid_platform") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -288,7 +289,7 @@ func TestResolveFQBN(t *testing.T) { t.Run("BoardAndBuildPropertiesForNonExistentCore", func(t *testing.T) { // Test a board referenced from a non-existent core // Note that ResolveFQBN does not actually check this currently - fqbn, err := cores.ParseFQBN("referenced:avr:dummy_invalid_core") + fqbn, err := fqbn.Parse("referenced:avr:dummy_invalid_core") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -306,7 +307,7 @@ func TestResolveFQBN(t *testing.T) { }) t.Run("AddBuildBoardPropertyIfMissing", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("my_avr_platform:avr:mymega") + fqbn, err := fqbn.Parse("my_avr_platform:avr:mymega") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -324,7 +325,7 @@ func TestResolveFQBN(t *testing.T) { }) t.Run("AddBuildBoardPropertyIfNotMissing", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("my_avr_platform:avr:mymega:cpu=atmega1280") + fqbn, err := fqbn.Parse("my_avr_platform:avr:mymega:cpu=atmega1280") require.Nil(t, err) require.NotNil(t, fqbn) pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) @@ -813,7 +814,7 @@ func TestLegacyPackageConversionToPluggableDiscovery(t *testing.T) { defer release() { - fqbn, err := cores.ParseFQBN("esp32:esp32:esp32") + fqbn, err := fqbn.Parse("esp32:esp32:esp32") require.NoError(t, err) require.NotNil(t, fqbn) _, platformRelease, board, _, _, err := pme.ResolveFQBN(fqbn) @@ -836,7 +837,7 @@ func TestLegacyPackageConversionToPluggableDiscovery(t *testing.T) { require.Equal(t, "{network_cmd} -i \"{upload.port.address}\" -p \"{upload.port.properties.port}\" \"--auth={upload.field.password}\" -f \"{build.path}/{build.project_name}.bin\"", platformProps.Get("tools.esptool__pluggable_network.upload.pattern")) } { - fqbn, err := cores.ParseFQBN("esp8266:esp8266:generic") + fqbn, err := fqbn.Parse("esp8266:esp8266:generic") require.NoError(t, err) require.NotNil(t, fqbn) _, platformRelease, board, _, _, err := pme.ResolveFQBN(fqbn) @@ -858,7 +859,7 @@ func TestLegacyPackageConversionToPluggableDiscovery(t *testing.T) { require.Equal(t, "\"{network_cmd}\" -I \"{runtime.platform.path}/tools/espota.py\" -i \"{upload.port.address}\" -p \"{upload.port.properties.port}\" \"--auth={upload.field.password}\" -f \"{build.path}/{build.project_name}.bin\"", platformProps.Get("tools.esptool__pluggable_network.upload.pattern")) } { - fqbn, err := cores.ParseFQBN("arduino:avr:uno") + fqbn, err := fqbn.Parse("arduino:avr:uno") require.NoError(t, err) require.NotNil(t, fqbn) _, platformRelease, board, _, _, err := pme.ResolveFQBN(fqbn) @@ -888,7 +889,7 @@ func TestVariantAndCoreSelection(t *testing.T) { // build.core test suite t.Run("CoreWithoutSubstitutions", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("test2:avr:test") + fqbn, err := fqbn.Parse("test2:avr:test") require.NoError(t, err) require.NotNil(t, fqbn) _, _, _, buildProps, _, err := pme.ResolveFQBN(fqbn) @@ -897,7 +898,7 @@ func TestVariantAndCoreSelection(t *testing.T) { requireSameFile(buildProps.GetPath("build.core.path"), dataDir1.Join("packages", "test2", "hardware", "avr", "1.0.0", "cores", "arduino")) }) t.Run("CoreWithSubstitutions", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("test2:avr:test2") + fqbn, err := fqbn.Parse("test2:avr:test2") require.NoError(t, err) require.NotNil(t, fqbn) _, _, _, buildProps, _, err := pme.ResolveFQBN(fqbn) @@ -907,7 +908,7 @@ func TestVariantAndCoreSelection(t *testing.T) { requireSameFile(buildProps.GetPath("build.core.path"), dataDir1.Join("packages", "test2", "hardware", "avr", "1.0.0", "cores", "arduino")) }) t.Run("CoreWithSubstitutionsAndDefaultOption", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("test2:avr:test3") + fqbn, err := fqbn.Parse("test2:avr:test3") require.NoError(t, err) require.NotNil(t, fqbn) _, _, _, buildProps, _, err := pme.ResolveFQBN(fqbn) @@ -917,7 +918,7 @@ func TestVariantAndCoreSelection(t *testing.T) { requireSameFile(buildProps.GetPath("build.core.path"), dataDir1.Join("packages", "test2", "hardware", "avr", "1.0.0", "cores", "arduino")) }) t.Run("CoreWithSubstitutionsAndNonDefaultOption", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("test2:avr:test3:core=referenced") + fqbn, err := fqbn.Parse("test2:avr:test3:core=referenced") require.NoError(t, err) require.NotNil(t, fqbn) _, _, _, buildProps, _, err := pme.ResolveFQBN(fqbn) @@ -929,7 +930,7 @@ func TestVariantAndCoreSelection(t *testing.T) { // build.variant test suite t.Run("VariantWithoutSubstitutions", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("test2:avr:test4") + fqbn, err := fqbn.Parse("test2:avr:test4") require.NoError(t, err) require.NotNil(t, fqbn) _, _, _, buildProps, _, err := pme.ResolveFQBN(fqbn) @@ -938,7 +939,7 @@ func TestVariantAndCoreSelection(t *testing.T) { requireSameFile(buildProps.GetPath("build.variant.path"), dataDir1.Join("packages", "test2", "hardware", "avr", "1.0.0", "variants", "standard")) }) t.Run("VariantWithSubstitutions", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("test2:avr:test5") + fqbn, err := fqbn.Parse("test2:avr:test5") require.NoError(t, err) require.NotNil(t, fqbn) _, _, _, buildProps, _, err := pme.ResolveFQBN(fqbn) @@ -948,7 +949,7 @@ func TestVariantAndCoreSelection(t *testing.T) { requireSameFile(buildProps.GetPath("build.variant.path"), dataDir1.Join("packages", "test2", "hardware", "avr", "1.0.0", "variants", "standard")) }) t.Run("VariantWithSubstitutionsAndDefaultOption", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("test2:avr:test6") + fqbn, err := fqbn.Parse("test2:avr:test6") require.NoError(t, err) require.NotNil(t, fqbn) _, _, _, buildProps, _, err := pme.ResolveFQBN(fqbn) @@ -958,7 +959,7 @@ func TestVariantAndCoreSelection(t *testing.T) { requireSameFile(buildProps.GetPath("build.variant.path"), dataDir1.Join("packages", "test2", "hardware", "avr", "1.0.0", "variants", "standard")) }) t.Run("VariantWithSubstitutionsAndNonDefaultOption", func(t *testing.T) { - fqbn, err := cores.ParseFQBN("test2:avr:test6:variant=referenced") + fqbn, err := fqbn.Parse("test2:avr:test6:variant=referenced") require.NoError(t, err) require.NotNil(t, fqbn) _, _, _, buildProps, _, err := pme.ResolveFQBN(fqbn) diff --git a/internal/cli/board/list.go b/internal/cli/board/list.go index 7d0c0c69082..9bd6fc37f22 100644 --- a/internal/cli/board/list.go +++ b/internal/cli/board/list.go @@ -24,13 +24,13 @@ import ( "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/commands/cmderrors" - "github.com/arduino/arduino-cli/internal/arduino/cores" "github.com/arduino/arduino-cli/internal/cli/arguments" "github.com/arduino/arduino-cli/internal/cli/feedback" "github.com/arduino/arduino-cli/internal/cli/feedback/result" "github.com/arduino/arduino-cli/internal/cli/feedback/table" "github.com/arduino/arduino-cli/internal/cli/instance" "github.com/arduino/arduino-cli/internal/i18n" + "github.com/arduino/arduino-cli/pkg/fqbn" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -159,9 +159,9 @@ func (dr listResult) String() string { // to improve the user experience, show on a dedicated column // the name of the core supporting the board detected var coreName = "" - fqbn, err := cores.ParseFQBN(b.Fqbn) + fqbn, err := fqbn.Parse(b.Fqbn) if err == nil { - coreName = fmt.Sprintf("%s:%s", fqbn.Package, fqbn.PlatformArch) + coreName = fmt.Sprintf("%s:%s", fqbn.Packager, fqbn.Architecture) } t.AddRow(address, protocol, protocolLabel, board, fqbn, coreName) @@ -215,9 +215,9 @@ func (dr watchEventResult) String() string { // to improve the user experience, show on a dedicated column // the name of the core supporting the board detected var coreName = "" - fqbn, err := cores.ParseFQBN(b.Fqbn) + fqbn, err := fqbn.Parse(b.Fqbn) if err == nil { - coreName = fmt.Sprintf("%s:%s", fqbn.Package, fqbn.PlatformArch) + coreName = fmt.Sprintf("%s:%s", fqbn.Packager, fqbn.Architecture) } t.AddRow(address, protocol, event, board, fqbn, coreName) diff --git a/internal/arduino/cores/fqbn.go b/pkg/fqbn/fqbn.go similarity index 80% rename from internal/arduino/cores/fqbn.go rename to pkg/fqbn/fqbn.go index 0db32f45cb0..14fa1b4a58b 100644 --- a/internal/arduino/cores/fqbn.go +++ b/pkg/fqbn/fqbn.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package cores +package fqbn import ( "errors" @@ -24,35 +24,35 @@ import ( properties "github.com/arduino/go-properties-orderedmap" ) -// FQBN represents a Board with a specific configuration +// FQBN represents an Fully Qualified Board Name string type FQBN struct { - Package string - PlatformArch string + Packager string + Architecture string BoardID string Configs *properties.Map } -// MustParseFQBN extract an FQBN object from the input string +// MustParse parse an FQBN string from the input string // or panics if the input is not a valid FQBN. -func MustParseFQBN(fqbnIn string) *FQBN { - res, err := ParseFQBN(fqbnIn) +func MustParse(fqbnIn string) *FQBN { + res, err := Parse(fqbnIn) if err != nil { panic(err) } return res } -// ParseFQBN extract an FQBN object from the input string -func ParseFQBN(fqbnIn string) (*FQBN, error) { - // Split fqbn +// Parse parses an FQBN string from the input string +func Parse(fqbnIn string) (*FQBN, error) { + // Split fqbn parts fqbnParts := strings.Split(fqbnIn, ":") if len(fqbnParts) < 3 || len(fqbnParts) > 4 { return nil, errors.New(i18n.Tr("not an FQBN: %s", fqbnIn)) } fqbn := &FQBN{ - Package: fqbnParts[0], - PlatformArch: fqbnParts[1], + Packager: fqbnParts[0], + Architecture: fqbnParts[1], BoardID: fqbnParts[2], Configs: properties.NewMap(), } @@ -91,29 +91,17 @@ func ParseFQBN(fqbnIn string) (*FQBN, error) { return fqbn, nil } -func (fqbn *FQBN) String() string { - res := fqbn.StringWithoutConfig() - if fqbn.Configs.Size() > 0 { - sep := ":" - for _, k := range fqbn.Configs.Keys() { - res += sep + k + "=" + fqbn.Configs.Get(k) - sep = "," - } - } - return res -} - // Clone returns a copy of this FQBN. func (fqbn *FQBN) Clone() *FQBN { return &FQBN{ - Package: fqbn.Package, - PlatformArch: fqbn.PlatformArch, + Packager: fqbn.Packager, + Architecture: fqbn.Architecture, BoardID: fqbn.BoardID, Configs: fqbn.Configs.Clone(), } } -// Match check if the target FQBN corresponds to the receiver one. +// Match checks if the target FQBN equals to this one. // The core parts are checked for exact equality while board options are loosely // matched: the set of boards options of the target must be fully contained within // the one of the receiver and their values must be equal. @@ -122,10 +110,8 @@ func (fqbn *FQBN) Match(target *FQBN) bool { return false } - searchedProperties := target.Configs.Clone() - actualConfigs := fqbn.Configs.AsMap() - for neededKey, neededValue := range searchedProperties.AsMap() { - targetValue, hasKey := actualConfigs[neededKey] + for neededKey, neededValue := range target.Configs.AsMap() { + targetValue, hasKey := fqbn.Configs.GetOk(neededKey) if !hasKey || targetValue != neededValue { return false } @@ -135,5 +121,18 @@ func (fqbn *FQBN) Match(target *FQBN) bool { // StringWithoutConfig returns the FQBN without the Config part func (fqbn *FQBN) StringWithoutConfig() string { - return fqbn.Package + ":" + fqbn.PlatformArch + ":" + fqbn.BoardID + return fqbn.Packager + ":" + fqbn.Architecture + ":" + fqbn.BoardID +} + +// String returns the FQBN as a string +func (fqbn *FQBN) String() string { + res := fqbn.StringWithoutConfig() + if fqbn.Configs.Size() > 0 { + sep := ":" + for _, k := range fqbn.Configs.Keys() { + res += sep + k + "=" + fqbn.Configs.Get(k) + sep = "," + } + } + return res } diff --git a/internal/arduino/cores/fqbn_test.go b/pkg/fqbn/fqbn_test.go similarity index 71% rename from internal/arduino/cores/fqbn_test.go rename to pkg/fqbn/fqbn_test.go index c7165af064a..7c5bc21fbf6 100644 --- a/internal/arduino/cores/fqbn_test.go +++ b/pkg/fqbn/fqbn_test.go @@ -13,67 +13,68 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package cores +package fqbn_test import ( "testing" + "github.com/arduino/arduino-cli/pkg/fqbn" "github.com/stretchr/testify/require" ) func TestFQBN(t *testing.T) { - a, err := ParseFQBN("arduino:avr:uno") + a, err := fqbn.Parse("arduino:avr:uno") require.Equal(t, "arduino:avr:uno", a.String()) require.NoError(t, err) - require.Equal(t, a.Package, "arduino") - require.Equal(t, a.PlatformArch, "avr") + require.Equal(t, a.Packager, "arduino") + require.Equal(t, a.Architecture, "avr") require.Equal(t, a.BoardID, "uno") require.Zero(t, a.Configs.Size()) // Allow empty platforms or packages (aka. vendors + architectures) - b1, err := ParseFQBN("arduino::uno") + b1, err := fqbn.Parse("arduino::uno") require.Equal(t, "arduino::uno", b1.String()) require.NoError(t, err) - require.Equal(t, b1.Package, "arduino") - require.Equal(t, b1.PlatformArch, "") + require.Equal(t, b1.Packager, "arduino") + require.Equal(t, b1.Architecture, "") require.Equal(t, b1.BoardID, "uno") require.Zero(t, b1.Configs.Size()) - b2, err := ParseFQBN(":avr:uno") + b2, err := fqbn.Parse(":avr:uno") require.Equal(t, ":avr:uno", b2.String()) require.NoError(t, err) - require.Equal(t, b2.Package, "") - require.Equal(t, b2.PlatformArch, "avr") + require.Equal(t, b2.Packager, "") + require.Equal(t, b2.Architecture, "avr") require.Equal(t, b2.BoardID, "uno") require.Zero(t, b2.Configs.Size()) - b3, err := ParseFQBN("::uno") + b3, err := fqbn.Parse("::uno") require.Equal(t, "::uno", b3.String()) require.NoError(t, err) - require.Equal(t, b3.Package, "") - require.Equal(t, b3.PlatformArch, "") + require.Equal(t, b3.Packager, "") + require.Equal(t, b3.Architecture, "") require.Equal(t, b3.BoardID, "uno") require.Zero(t, b3.Configs.Size()) // Do not allow missing board identifier - _, err = ParseFQBN("arduino:avr:") + _, err = fqbn.Parse("arduino:avr:") require.Error(t, err) // Do not allow partial fqbn - _, err = ParseFQBN("arduino") + _, err = fqbn.Parse("arduino") require.Error(t, err) - _, err = ParseFQBN("arduino:avr") + _, err = fqbn.Parse("arduino:avr") require.Error(t, err) // Keeps the config keys order - s1, err := ParseFQBN("arduino:avr:uno:d=x,b=x,a=x,e=x,c=x") + s1, err := fqbn.Parse("arduino:avr:uno:d=x,b=x,a=x,e=x,c=x") require.NoError(t, err) require.Equal(t, "arduino:avr:uno:d=x,b=x,a=x,e=x,c=x", s1.String()) require.Equal(t, "properties.Map{\n \"d\": \"x\",\n \"b\": \"x\",\n \"a\": \"x\",\n \"e\": \"x\",\n \"c\": \"x\",\n}", s1.Configs.Dump()) - s2, err := ParseFQBN("arduino:avr:uno:a=x,b=x,c=x,d=x,e=x") + s2, err := fqbn.Parse("arduino:avr:uno:a=x,b=x,c=x,d=x,e=x") require.NoError(t, err) require.Equal(t, "arduino:avr:uno:a=x,b=x,c=x,d=x,e=x", s2.String()) require.Equal(t, @@ -85,53 +86,53 @@ func TestFQBN(t *testing.T) { require.NotEqual(t, s1.String(), s2.String()) // Test configs - c, err := ParseFQBN("arduino:avr:uno:cpu=atmega") + c, err := fqbn.Parse("arduino:avr:uno:cpu=atmega") require.Equal(t, "arduino:avr:uno:cpu=atmega", c.String()) require.NoError(t, err) - require.Equal(t, c.Package, "arduino") - require.Equal(t, c.PlatformArch, "avr") + require.Equal(t, c.Packager, "arduino") + require.Equal(t, c.Architecture, "avr") require.Equal(t, c.BoardID, "uno") require.Equal(t, "properties.Map{\n \"cpu\": \"atmega\",\n}", c.Configs.Dump()) - d, err := ParseFQBN("arduino:avr:uno:cpu=atmega,speed=1000") + d, err := fqbn.Parse("arduino:avr:uno:cpu=atmega,speed=1000") require.Equal(t, "arduino:avr:uno:cpu=atmega,speed=1000", d.String()) require.NoError(t, err) - require.Equal(t, d.Package, "arduino") - require.Equal(t, d.PlatformArch, "avr") + require.Equal(t, d.Packager, "arduino") + require.Equal(t, d.Architecture, "avr") require.Equal(t, d.BoardID, "uno") require.Equal(t, "properties.Map{\n \"cpu\": \"atmega\",\n \"speed\": \"1000\",\n}", d.Configs.Dump()) // Do not allow empty keys or missing values in config - _, err = ParseFQBN("arduino:avr:uno:") + _, err = fqbn.Parse("arduino:avr:uno:") require.Error(t, err) - _, err = ParseFQBN("arduino:avr:uno,") + _, err = fqbn.Parse("arduino:avr:uno,") require.Error(t, err) - _, err = ParseFQBN("arduino:avr:uno:cpu") + _, err = fqbn.Parse("arduino:avr:uno:cpu") require.Error(t, err) - _, err = ParseFQBN("arduino:avr:uno:=atmega") + _, err = fqbn.Parse("arduino:avr:uno:=atmega") require.Error(t, err) - _, err = ParseFQBN("arduino:avr:uno:cpu=atmega,") + _, err = fqbn.Parse("arduino:avr:uno:cpu=atmega,") require.Error(t, err) - _, err = ParseFQBN("arduino:avr:uno:cpu=atmega,speed") + _, err = fqbn.Parse("arduino:avr:uno:cpu=atmega,speed") require.Error(t, err) - _, err = ParseFQBN("arduino:avr:uno:cpu=atmega,=1000") + _, err = fqbn.Parse("arduino:avr:uno:cpu=atmega,=1000") require.Error(t, err) // Allow keys with empty values - e, err := ParseFQBN("arduino:avr:uno:cpu=") + e, err := fqbn.Parse("arduino:avr:uno:cpu=") require.Equal(t, "arduino:avr:uno:cpu=", e.String()) require.NoError(t, err) - require.Equal(t, e.Package, "arduino") - require.Equal(t, e.PlatformArch, "avr") + require.Equal(t, e.Packager, "arduino") + require.Equal(t, e.Architecture, "avr") require.Equal(t, e.BoardID, "uno") require.Equal(t, "properties.Map{\n \"cpu\": \"\",\n}", e.Configs.Dump()) // Allow "=" in config values - f, err := ParseFQBN("arduino:avr:uno:cpu=atmega,speed=1000,extra=core=arduino") + f, err := fqbn.Parse("arduino:avr:uno:cpu=atmega,speed=1000,extra=core=arduino") require.Equal(t, "arduino:avr:uno:cpu=atmega,speed=1000,extra=core=arduino", f.String()) require.NoError(t, err) - require.Equal(t, f.Package, "arduino") - require.Equal(t, f.PlatformArch, "avr") + require.Equal(t, f.Packager, "arduino") + require.Equal(t, f.Architecture, "avr") require.Equal(t, f.BoardID, "uno") require.Equal(t, "properties.Map{\n \"cpu\": \"atmega\",\n \"speed\": \"1000\",\n \"extra\": \"core=arduino\",\n}", @@ -148,9 +149,9 @@ func TestMatch(t *testing.T) { } for _, pair := range expectedMatches { - a, err := ParseFQBN(pair[0]) + a, err := fqbn.Parse(pair[0]) require.NoError(t, err) - b, err := ParseFQBN(pair[1]) + b, err := fqbn.Parse(pair[1]) require.NoError(t, err) require.True(t, b.Match(a)) } @@ -164,9 +165,9 @@ func TestMatch(t *testing.T) { } for _, pair := range expectedMismatches { - a, err := ParseFQBN(pair[0]) + a, err := fqbn.Parse(pair[0]) require.NoError(t, err) - b, err := ParseFQBN(pair[1]) + b, err := fqbn.Parse(pair[1]) require.NoError(t, err) require.False(t, b.Match(a)) } @@ -175,14 +176,14 @@ func TestMatch(t *testing.T) { func TestValidCharacters(t *testing.T) { // These FQBNs contain valid characters validFqbns := []string{"ardui_no:av_r:un_o", "arduin.o:av.r:un.o", "arduin-o:av-r:un-o", "arduin-o:av-r:un-o:a=b=c=d"} - for _, fqbn := range validFqbns { - _, err := ParseFQBN(fqbn) + for _, validFqbn := range validFqbns { + _, err := fqbn.Parse(validFqbn) require.NoError(t, err) } // These FQBNs contain invalid characters invalidFqbns := []string{"arduin-o:av-r:un=o", "arduin?o:av-r:uno", "arduino:av*r:uno"} - for _, fqbn := range invalidFqbns { - _, err := ParseFQBN(fqbn) + for _, validFqbn := range invalidFqbns { + _, err := fqbn.Parse(validFqbn) require.Error(t, err) } } From 3e13de952621bf94433449e1e24a87dea173b2ad Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 27 Nov 2024 18:17:07 +0100 Subject: [PATCH 2/6] 100% test coverage --- pkg/fqbn/fqbn_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/pkg/fqbn/fqbn_test.go b/pkg/fqbn/fqbn_test.go index 7c5bc21fbf6..be76dad2f27 100644 --- a/pkg/fqbn/fqbn_test.go +++ b/pkg/fqbn/fqbn_test.go @@ -137,6 +137,27 @@ func TestFQBN(t *testing.T) { require.Equal(t, "properties.Map{\n \"cpu\": \"atmega\",\n \"speed\": \"1000\",\n \"extra\": \"core=arduino\",\n}", f.Configs.Dump()) + + // Check invalid characters in config keys + _, err = fqbn.Parse("arduino:avr:uno:cpu@=atmega") + require.Error(t, err) + _, err = fqbn.Parse("arduino:avr:uno:cpu@atmega") + require.Error(t, err) + _, err = fqbn.Parse("arduino:avr:uno:cpu=atmega,speed@=1000") + require.Error(t, err) + _, err = fqbn.Parse("arduino:avr:uno:cpu=atmega,speed@1000") + require.Error(t, err) + + // Check invalid characters in config values + _, err = fqbn.Parse("arduino:avr:uno:cpu=atmega@") + require.Error(t, err) + _, err = fqbn.Parse("arduino:avr:uno:cpu=atmega@extra") + require.Error(t, err) + _, err = fqbn.Parse("arduino:avr:uno:cpu=atmega,speed=1000@") + require.Error(t, err) + _, err = fqbn.Parse("arduino:avr:uno:cpu=atmega,speed=1000@extra") + require.Error(t, err) + } func TestMatch(t *testing.T) { @@ -187,3 +208,21 @@ func TestValidCharacters(t *testing.T) { require.Error(t, err) } } + +func TestMustParse(t *testing.T) { + require.NotPanics(t, func() { fqbn.MustParse("arduino:avr:uno") }) + require.Panics(t, func() { fqbn.MustParse("ard=uino:avr=:u=no") }) +} + +func TestClone(t *testing.T) { + a, err := fqbn.Parse("arduino:avr:uno:opt1=1,opt2=2") + require.NoError(t, err) + b := a.Clone() + require.True(t, b.Match(a)) + require.True(t, a.Match(b)) + + c, err := fqbn.Parse("arduino:avr:uno:opt1=1,opt2=2,opt3=3") + require.NoError(t, err) + require.True(t, c.Match(a)) + require.False(t, a.Match(c)) +} From dd8c35ac1cb2da77bd668ca04f80c2034781f8a0 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 29 Nov 2024 10:53:38 +0100 Subject: [PATCH 3/6] Precompile validation regexp --- pkg/fqbn/fqbn.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/fqbn/fqbn.go b/pkg/fqbn/fqbn.go index 14fa1b4a58b..8773272dd04 100644 --- a/pkg/fqbn/fqbn.go +++ b/pkg/fqbn/fqbn.go @@ -42,6 +42,9 @@ func MustParse(fqbnIn string) *FQBN { return res } +var fqbnValidationRegex = regexp.MustCompile(`^[a-zA-Z0-9_.-]*$`) +var valueValidationRegex = regexp.MustCompile(`^[a-zA-Z0-9=_.-]*$`) + // Parse parses an FQBN string from the input string func Parse(fqbnIn string) (*FQBN, error) { // Split fqbn parts @@ -60,7 +63,6 @@ func Parse(fqbnIn string) (*FQBN, error) { return nil, errors.New(i18n.Tr("empty board identifier")) } // Check if the fqbn contains invalid characters - fqbnValidationRegex := regexp.MustCompile(`^[a-zA-Z0-9_.-]*$`) for i := 0; i < 3; i++ { if !fqbnValidationRegex.MatchString(fqbnParts[i]) { return nil, errors.New(i18n.Tr("fqbn's field %s contains an invalid character", fqbnParts[i])) @@ -81,7 +83,6 @@ func Parse(fqbnIn string) (*FQBN, error) { return nil, errors.New(i18n.Tr("config key %s contains an invalid character", k)) } // The config value can also contain the = symbol - valueValidationRegex := regexp.MustCompile(`^[a-zA-Z0-9=_.-]*$`) if !valueValidationRegex.MatchString(v) { return nil, errors.New(i18n.Tr("config value %s contains an invalid character", v)) } From a3c9f72668fbb4134da6e6c0b3ac9aaba46e7916 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 29 Nov 2024 11:15:49 +0100 Subject: [PATCH 4/6] Remove logrus dependency from i18n --- internal/i18n/detect_windows.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/i18n/detect_windows.go b/internal/i18n/detect_windows.go index 84bc3af7997..f0adbce7718 100644 --- a/internal/i18n/detect_windows.go +++ b/internal/i18n/detect_windows.go @@ -19,14 +19,12 @@ import ( "strings" "syscall" "unsafe" - - "github.com/sirupsen/logrus" ) func getLocaleIdentifier() string { defer func() { if r := recover(); r != nil { - logrus.WithField("error", r).Errorf("Failed to get windows user locale") + // ignore error and do not panic } }() From b87a21542de2b3c29eefcd04ae9bcefedf0fbc19 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 29 Nov 2024 11:31:52 +0100 Subject: [PATCH 5/6] Isolate locale-handling functions from i18n interface This changes allows to make a clean i18n package (without dependency on a specific implementation of the translation package) that, in turn, allows to export packages that internally use i18n with the minimal dependency load. --- Taskfile.yml | 10 ++--- commands/instances.go | 3 +- internal/i18n/i18n.go | 41 +++++++++---------- internal/i18n/i18n_test.go | 7 ++-- internal/{i18n => locales}/README.md | 0 internal/{i18n => locales}/cmd/ast/parser.go | 2 +- .../cmd/commands/catalog/catalog.go | 0 .../cmd/commands/catalog/generate_catalog.go | 2 +- .../{i18n => locales}/cmd/commands/root.go | 4 +- .../cmd/commands/transifex/pull_transifex.go | 0 .../cmd/commands/transifex/push_transifex.go | 0 .../cmd/commands/transifex/transifex.go | 0 internal/{i18n => locales}/cmd/main.go | 2 +- internal/{i18n => locales}/cmd/po/catalog.go | 0 .../{i18n => locales}/cmd/po/catalog_test.go | 0 internal/{i18n => locales}/cmd/po/merge.go | 0 .../{i18n => locales}/cmd/po/merge_test.go | 0 internal/{i18n => locales}/cmd/po/parser.go | 0 .../{i18n => locales}/cmd/po/parser_test.go | 0 internal/{i18n => locales}/convert.go | 2 +- internal/{i18n => locales}/convert_test.go | 2 +- internal/{i18n => locales}/data/.gitkeep | 0 internal/{i18n => locales}/data/README.md | 0 internal/{i18n => locales}/data/ar.po | 0 internal/{i18n => locales}/data/be.po | 0 internal/{i18n => locales}/data/de.po | 0 internal/{i18n => locales}/data/en.po | 0 internal/{i18n => locales}/data/es.po | 0 internal/{i18n => locales}/data/fr.po | 0 internal/{i18n => locales}/data/he.po | 0 internal/{i18n => locales}/data/it_IT.po | 0 internal/{i18n => locales}/data/ja.po | 0 internal/{i18n => locales}/data/kk.po | 0 internal/{i18n => locales}/data/ko.po | 0 internal/{i18n => locales}/data/lb.po | 0 internal/{i18n => locales}/data/mn.po | 0 internal/{i18n => locales}/data/my_MM.po | 0 internal/{i18n => locales}/data/ne.po | 0 internal/{i18n => locales}/data/pl.po | 0 internal/{i18n => locales}/data/pt.po | 0 internal/{i18n => locales}/data/pt_BR.po | 0 internal/{i18n => locales}/data/ru.po | 0 internal/{i18n => locales}/data/zh.po | 0 internal/{i18n => locales}/data/zh_TW.po | 0 internal/{i18n => locales}/detect.go | 2 +- .../{i18n => locales}/detect_cgo_darwin.go | 2 +- internal/{i18n => locales}/detect_freebsd.go | 2 +- internal/{i18n => locales}/detect_linux.go | 2 +- .../{i18n => locales}/detect_nocgo_darwin.go | 2 +- internal/{i18n => locales}/detect_windows.go | 2 +- internal/locales/i18n.go | 39 ++++++++++++++++++ internal/{i18n => locales}/locale.go | 14 +++---- internal/{i18n => locales}/locale_test.go | 2 +- main.go | 3 +- 54 files changed, 90 insertions(+), 55 deletions(-) rename internal/{i18n => locales}/README.md (100%) rename internal/{i18n => locales}/cmd/ast/parser.go (97%) rename internal/{i18n => locales}/cmd/commands/catalog/catalog.go (100%) rename internal/{i18n => locales}/cmd/commands/catalog/generate_catalog.go (95%) rename internal/{i18n => locales}/cmd/commands/root.go (87%) rename internal/{i18n => locales}/cmd/commands/transifex/pull_transifex.go (100%) rename internal/{i18n => locales}/cmd/commands/transifex/push_transifex.go (100%) rename internal/{i18n => locales}/cmd/commands/transifex/transifex.go (100%) rename internal/{i18n => locales}/cmd/main.go (93%) rename internal/{i18n => locales}/cmd/po/catalog.go (100%) rename internal/{i18n => locales}/cmd/po/catalog_test.go (100%) rename internal/{i18n => locales}/cmd/po/merge.go (100%) rename internal/{i18n => locales}/cmd/po/merge_test.go (100%) rename internal/{i18n => locales}/cmd/po/parser.go (100%) rename internal/{i18n => locales}/cmd/po/parser_test.go (100%) rename internal/{i18n => locales}/convert.go (98%) rename internal/{i18n => locales}/convert_test.go (99%) rename internal/{i18n => locales}/data/.gitkeep (100%) rename internal/{i18n => locales}/data/README.md (100%) rename internal/{i18n => locales}/data/ar.po (100%) rename internal/{i18n => locales}/data/be.po (100%) rename internal/{i18n => locales}/data/de.po (100%) rename internal/{i18n => locales}/data/en.po (100%) rename internal/{i18n => locales}/data/es.po (100%) rename internal/{i18n => locales}/data/fr.po (100%) rename internal/{i18n => locales}/data/he.po (100%) rename internal/{i18n => locales}/data/it_IT.po (100%) rename internal/{i18n => locales}/data/ja.po (100%) rename internal/{i18n => locales}/data/kk.po (100%) rename internal/{i18n => locales}/data/ko.po (100%) rename internal/{i18n => locales}/data/lb.po (100%) rename internal/{i18n => locales}/data/mn.po (100%) rename internal/{i18n => locales}/data/my_MM.po (100%) rename internal/{i18n => locales}/data/ne.po (100%) rename internal/{i18n => locales}/data/pl.po (100%) rename internal/{i18n => locales}/data/pt.po (100%) rename internal/{i18n => locales}/data/pt_BR.po (100%) rename internal/{i18n => locales}/data/ru.po (100%) rename internal/{i18n => locales}/data/zh.po (100%) rename internal/{i18n => locales}/data/zh_TW.po (100%) rename internal/{i18n => locales}/detect.go (98%) rename internal/{i18n => locales}/detect_cgo_darwin.go (98%) rename internal/{i18n => locales}/detect_freebsd.go (98%) rename internal/{i18n => locales}/detect_linux.go (98%) rename internal/{i18n => locales}/detect_nocgo_darwin.go (98%) rename internal/{i18n => locales}/detect_windows.go (98%) create mode 100644 internal/locales/i18n.go rename internal/{i18n => locales}/locale.go (93%) rename internal/{i18n => locales}/locale_test.go (98%) diff --git a/Taskfile.yml b/Taskfile.yml index 095cae2dd87..6dac2c66d54 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -309,24 +309,24 @@ tasks: i18n:update: desc: Updates i18n files cmds: - - go run ./internal/i18n/cmd/main.go catalog generate . > ./internal/i18n/data/en.po + - go run ./internal/locales/cmd/main.go catalog generate . > ./internal/locales/data/en.po i18n:pull: desc: Pull i18n files from transifex cmds: - - go run ./internal/i18n/cmd/main.go transifex pull ./internal/i18n/data + - go run ./internal/locales/cmd/main.go transifex pull ./internal/locales/data i18n:push: desc: Push i18n files to transifex cmds: - - go run ./internal/i18n/cmd/main.go transifex push ./internal/i18n/data + - go run ./internal/locales/cmd/main.go transifex push ./internal/locales/data i18n:check: desc: Check if the i18n message catalog was updated cmds: - task: i18n:pull - - git add -N ./internal/i18n/data - - git diff --exit-code ./internal/i18n/data + - git add -N ./internal/locales/data + - git diff --exit-code ./internal/locales/data # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/check-mkdocs-task/Taskfile.yml website:check: diff --git a/commands/instances.go b/commands/instances.go index 23f42be9638..3c023301cd4 100644 --- a/commands/instances.go +++ b/commands/instances.go @@ -38,6 +38,7 @@ import ( "github.com/arduino/arduino-cli/internal/arduino/sketch" "github.com/arduino/arduino-cli/internal/arduino/utils" "github.com/arduino/arduino-cli/internal/i18n" + "github.com/arduino/arduino-cli/internal/locales" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" "github.com/sirupsen/logrus" @@ -420,7 +421,7 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor // language of the CLI if the locale is different // after started. if locale, ok, _ := s.settings.GetStringOk("locale"); ok { - i18n.Init(locale) + locales.Init(locale) } return nil diff --git a/internal/i18n/i18n.go b/internal/i18n/i18n.go index aa4f82edd33..f1941297b00 100644 --- a/internal/i18n/i18n.go +++ b/internal/i18n/i18n.go @@ -15,31 +15,28 @@ package i18n -// Init initializes the i18n module, setting the locale according to this order of preference: -// 1. Locale specified via the function call -// 2. OS Locale -// 3. en (default) -func Init(configLocale string) { - locales := supportedLocales() - if configLocale != "" { - if locale := findMatchingLocale(configLocale, locales); locale != "" { - setLocale(locale) - return - } - } - - if osLocale := getLocaleIdentifierFromOS(); osLocale != "" { - if locale := findMatchingLocale(osLocale, locales); locale != "" { - setLocale(locale) - return - } - } - - setLocale("en") +import "fmt" + +type Locale interface { + Get(msg string, args ...interface{}) string +} + +type nullLocale struct{} + +func (n nullLocale) Parse([]byte) {} + +func (n nullLocale) Get(msg string, args ...interface{}) string { + return fmt.Sprintf(msg, args...) +} + +var locale Locale = &nullLocale{} + +func SetLocale(l Locale) { + locale = l } // Tr returns msg translated to the selected locale // the msg argument must be a literal string func Tr(msg string, args ...interface{}) string { - return po.Get(msg, args...) + return locale.Get(msg, args...) } diff --git a/internal/i18n/i18n_test.go b/internal/i18n/i18n_test.go index 1ec157db01e..a2ae4c4d7b0 100644 --- a/internal/i18n/i18n_test.go +++ b/internal/i18n/i18n_test.go @@ -25,8 +25,9 @@ import ( ) func setPo(poFile string) { - po = gotext.NewPo() - po.Parse([]byte(poFile)) + dict := gotext.NewPo() + dict.Parse([]byte(poFile)) + SetLocale(dict) } func TestPoTranslation(t *testing.T) { @@ -39,7 +40,7 @@ func TestPoTranslation(t *testing.T) { } func TestNoLocaleSet(t *testing.T) { - po = gotext.NewPo() + locale = gotext.NewPo() require.Equal(t, "test-key", Tr("test-key")) } diff --git a/internal/i18n/README.md b/internal/locales/README.md similarity index 100% rename from internal/i18n/README.md rename to internal/locales/README.md diff --git a/internal/i18n/cmd/ast/parser.go b/internal/locales/cmd/ast/parser.go similarity index 97% rename from internal/i18n/cmd/ast/parser.go rename to internal/locales/cmd/ast/parser.go index d8d558cd975..69648c70c1b 100644 --- a/internal/i18n/cmd/ast/parser.go +++ b/internal/locales/cmd/ast/parser.go @@ -24,7 +24,7 @@ import ( "path/filepath" "strconv" - "github.com/arduino/arduino-cli/internal/i18n/cmd/po" + "github.com/arduino/arduino-cli/internal/locales/cmd/po" ) // GenerateCatalog generates the i18n message catalog for the go source files diff --git a/internal/i18n/cmd/commands/catalog/catalog.go b/internal/locales/cmd/commands/catalog/catalog.go similarity index 100% rename from internal/i18n/cmd/commands/catalog/catalog.go rename to internal/locales/cmd/commands/catalog/catalog.go diff --git a/internal/i18n/cmd/commands/catalog/generate_catalog.go b/internal/locales/cmd/commands/catalog/generate_catalog.go similarity index 95% rename from internal/i18n/cmd/commands/catalog/generate_catalog.go rename to internal/locales/cmd/commands/catalog/generate_catalog.go index 1c65c640ffc..27ac0e76d45 100644 --- a/internal/i18n/cmd/commands/catalog/generate_catalog.go +++ b/internal/locales/cmd/commands/catalog/generate_catalog.go @@ -19,7 +19,7 @@ import ( "os" "path/filepath" - "github.com/arduino/arduino-cli/internal/i18n/cmd/ast" + "github.com/arduino/arduino-cli/internal/locales/cmd/ast" "github.com/spf13/cobra" ) diff --git a/internal/i18n/cmd/commands/root.go b/internal/locales/cmd/commands/root.go similarity index 87% rename from internal/i18n/cmd/commands/root.go rename to internal/locales/cmd/commands/root.go index 14559dcfee9..fc5d8eb37e0 100644 --- a/internal/i18n/cmd/commands/root.go +++ b/internal/locales/cmd/commands/root.go @@ -16,8 +16,8 @@ package commands import ( - "github.com/arduino/arduino-cli/internal/i18n/cmd/commands/catalog" - "github.com/arduino/arduino-cli/internal/i18n/cmd/commands/transifex" + "github.com/arduino/arduino-cli/internal/locales/cmd/commands/catalog" + "github.com/arduino/arduino-cli/internal/locales/cmd/commands/transifex" "github.com/spf13/cobra" ) diff --git a/internal/i18n/cmd/commands/transifex/pull_transifex.go b/internal/locales/cmd/commands/transifex/pull_transifex.go similarity index 100% rename from internal/i18n/cmd/commands/transifex/pull_transifex.go rename to internal/locales/cmd/commands/transifex/pull_transifex.go diff --git a/internal/i18n/cmd/commands/transifex/push_transifex.go b/internal/locales/cmd/commands/transifex/push_transifex.go similarity index 100% rename from internal/i18n/cmd/commands/transifex/push_transifex.go rename to internal/locales/cmd/commands/transifex/push_transifex.go diff --git a/internal/i18n/cmd/commands/transifex/transifex.go b/internal/locales/cmd/commands/transifex/transifex.go similarity index 100% rename from internal/i18n/cmd/commands/transifex/transifex.go rename to internal/locales/cmd/commands/transifex/transifex.go diff --git a/internal/i18n/cmd/main.go b/internal/locales/cmd/main.go similarity index 93% rename from internal/i18n/cmd/main.go rename to internal/locales/cmd/main.go index 8752c9d668e..d31f1589e09 100644 --- a/internal/i18n/cmd/main.go +++ b/internal/locales/cmd/main.go @@ -19,7 +19,7 @@ import ( "fmt" "os" - "github.com/arduino/arduino-cli/internal/i18n/cmd/commands" + "github.com/arduino/arduino-cli/internal/locales/cmd/commands" ) func main() { diff --git a/internal/i18n/cmd/po/catalog.go b/internal/locales/cmd/po/catalog.go similarity index 100% rename from internal/i18n/cmd/po/catalog.go rename to internal/locales/cmd/po/catalog.go diff --git a/internal/i18n/cmd/po/catalog_test.go b/internal/locales/cmd/po/catalog_test.go similarity index 100% rename from internal/i18n/cmd/po/catalog_test.go rename to internal/locales/cmd/po/catalog_test.go diff --git a/internal/i18n/cmd/po/merge.go b/internal/locales/cmd/po/merge.go similarity index 100% rename from internal/i18n/cmd/po/merge.go rename to internal/locales/cmd/po/merge.go diff --git a/internal/i18n/cmd/po/merge_test.go b/internal/locales/cmd/po/merge_test.go similarity index 100% rename from internal/i18n/cmd/po/merge_test.go rename to internal/locales/cmd/po/merge_test.go diff --git a/internal/i18n/cmd/po/parser.go b/internal/locales/cmd/po/parser.go similarity index 100% rename from internal/i18n/cmd/po/parser.go rename to internal/locales/cmd/po/parser.go diff --git a/internal/i18n/cmd/po/parser_test.go b/internal/locales/cmd/po/parser_test.go similarity index 100% rename from internal/i18n/cmd/po/parser_test.go rename to internal/locales/cmd/po/parser_test.go diff --git a/internal/i18n/convert.go b/internal/locales/convert.go similarity index 98% rename from internal/i18n/convert.go rename to internal/locales/convert.go index 7b6d2e8dbdf..e7aa8227571 100644 --- a/internal/i18n/convert.go +++ b/internal/locales/convert.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package i18n +package locales import ( "regexp" diff --git a/internal/i18n/convert_test.go b/internal/locales/convert_test.go similarity index 99% rename from internal/i18n/convert_test.go rename to internal/locales/convert_test.go index 618fa977b3b..723d6118c2b 100644 --- a/internal/i18n/convert_test.go +++ b/internal/locales/convert_test.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package i18n +package locales import ( "fmt" diff --git a/internal/i18n/data/.gitkeep b/internal/locales/data/.gitkeep similarity index 100% rename from internal/i18n/data/.gitkeep rename to internal/locales/data/.gitkeep diff --git a/internal/i18n/data/README.md b/internal/locales/data/README.md similarity index 100% rename from internal/i18n/data/README.md rename to internal/locales/data/README.md diff --git a/internal/i18n/data/ar.po b/internal/locales/data/ar.po similarity index 100% rename from internal/i18n/data/ar.po rename to internal/locales/data/ar.po diff --git a/internal/i18n/data/be.po b/internal/locales/data/be.po similarity index 100% rename from internal/i18n/data/be.po rename to internal/locales/data/be.po diff --git a/internal/i18n/data/de.po b/internal/locales/data/de.po similarity index 100% rename from internal/i18n/data/de.po rename to internal/locales/data/de.po diff --git a/internal/i18n/data/en.po b/internal/locales/data/en.po similarity index 100% rename from internal/i18n/data/en.po rename to internal/locales/data/en.po diff --git a/internal/i18n/data/es.po b/internal/locales/data/es.po similarity index 100% rename from internal/i18n/data/es.po rename to internal/locales/data/es.po diff --git a/internal/i18n/data/fr.po b/internal/locales/data/fr.po similarity index 100% rename from internal/i18n/data/fr.po rename to internal/locales/data/fr.po diff --git a/internal/i18n/data/he.po b/internal/locales/data/he.po similarity index 100% rename from internal/i18n/data/he.po rename to internal/locales/data/he.po diff --git a/internal/i18n/data/it_IT.po b/internal/locales/data/it_IT.po similarity index 100% rename from internal/i18n/data/it_IT.po rename to internal/locales/data/it_IT.po diff --git a/internal/i18n/data/ja.po b/internal/locales/data/ja.po similarity index 100% rename from internal/i18n/data/ja.po rename to internal/locales/data/ja.po diff --git a/internal/i18n/data/kk.po b/internal/locales/data/kk.po similarity index 100% rename from internal/i18n/data/kk.po rename to internal/locales/data/kk.po diff --git a/internal/i18n/data/ko.po b/internal/locales/data/ko.po similarity index 100% rename from internal/i18n/data/ko.po rename to internal/locales/data/ko.po diff --git a/internal/i18n/data/lb.po b/internal/locales/data/lb.po similarity index 100% rename from internal/i18n/data/lb.po rename to internal/locales/data/lb.po diff --git a/internal/i18n/data/mn.po b/internal/locales/data/mn.po similarity index 100% rename from internal/i18n/data/mn.po rename to internal/locales/data/mn.po diff --git a/internal/i18n/data/my_MM.po b/internal/locales/data/my_MM.po similarity index 100% rename from internal/i18n/data/my_MM.po rename to internal/locales/data/my_MM.po diff --git a/internal/i18n/data/ne.po b/internal/locales/data/ne.po similarity index 100% rename from internal/i18n/data/ne.po rename to internal/locales/data/ne.po diff --git a/internal/i18n/data/pl.po b/internal/locales/data/pl.po similarity index 100% rename from internal/i18n/data/pl.po rename to internal/locales/data/pl.po diff --git a/internal/i18n/data/pt.po b/internal/locales/data/pt.po similarity index 100% rename from internal/i18n/data/pt.po rename to internal/locales/data/pt.po diff --git a/internal/i18n/data/pt_BR.po b/internal/locales/data/pt_BR.po similarity index 100% rename from internal/i18n/data/pt_BR.po rename to internal/locales/data/pt_BR.po diff --git a/internal/i18n/data/ru.po b/internal/locales/data/ru.po similarity index 100% rename from internal/i18n/data/ru.po rename to internal/locales/data/ru.po diff --git a/internal/i18n/data/zh.po b/internal/locales/data/zh.po similarity index 100% rename from internal/i18n/data/zh.po rename to internal/locales/data/zh.po diff --git a/internal/i18n/data/zh_TW.po b/internal/locales/data/zh_TW.po similarity index 100% rename from internal/i18n/data/zh_TW.po rename to internal/locales/data/zh_TW.po diff --git a/internal/i18n/detect.go b/internal/locales/detect.go similarity index 98% rename from internal/i18n/detect.go rename to internal/locales/detect.go index f35d4f1b94e..36279f1388b 100644 --- a/internal/i18n/detect.go +++ b/internal/locales/detect.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package i18n +package locales import ( "os" diff --git a/internal/i18n/detect_cgo_darwin.go b/internal/locales/detect_cgo_darwin.go similarity index 98% rename from internal/i18n/detect_cgo_darwin.go rename to internal/locales/detect_cgo_darwin.go index c9fd4ecefb9..7c613cf6135 100644 --- a/internal/i18n/detect_cgo_darwin.go +++ b/internal/locales/detect_cgo_darwin.go @@ -15,7 +15,7 @@ //go:build darwin && cgo -package i18n +package locales /* #cgo CFLAGS: -x objective-c diff --git a/internal/i18n/detect_freebsd.go b/internal/locales/detect_freebsd.go similarity index 98% rename from internal/i18n/detect_freebsd.go rename to internal/locales/detect_freebsd.go index 759509c5abe..4d03b8f3c92 100644 --- a/internal/i18n/detect_freebsd.go +++ b/internal/locales/detect_freebsd.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package i18n +package locales func getLocaleIdentifier() string { return getLocaleIdentifierFromEnv() diff --git a/internal/i18n/detect_linux.go b/internal/locales/detect_linux.go similarity index 98% rename from internal/i18n/detect_linux.go rename to internal/locales/detect_linux.go index 759509c5abe..4d03b8f3c92 100644 --- a/internal/i18n/detect_linux.go +++ b/internal/locales/detect_linux.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package i18n +package locales func getLocaleIdentifier() string { return getLocaleIdentifierFromEnv() diff --git a/internal/i18n/detect_nocgo_darwin.go b/internal/locales/detect_nocgo_darwin.go similarity index 98% rename from internal/i18n/detect_nocgo_darwin.go rename to internal/locales/detect_nocgo_darwin.go index f7ae977b19f..689b5e864c5 100644 --- a/internal/i18n/detect_nocgo_darwin.go +++ b/internal/locales/detect_nocgo_darwin.go @@ -15,7 +15,7 @@ //go:build darwin && !cgo -package i18n +package locales func getLocaleIdentifier() string { return getLocaleIdentifierFromEnv() diff --git a/internal/i18n/detect_windows.go b/internal/locales/detect_windows.go similarity index 98% rename from internal/i18n/detect_windows.go rename to internal/locales/detect_windows.go index f0adbce7718..42c667447d6 100644 --- a/internal/i18n/detect_windows.go +++ b/internal/locales/detect_windows.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package i18n +package locales import ( "strings" diff --git a/internal/locales/i18n.go b/internal/locales/i18n.go new file mode 100644 index 00000000000..8c7120a1771 --- /dev/null +++ b/internal/locales/i18n.go @@ -0,0 +1,39 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 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-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 locales + +// Init initializes the i18n module, setting the locale according to this order of preference: +// 1. Locale specified via the function call +// 2. OS Locale +// 3. en (default) +func Init(configLocale string) { + locales := supportedLocales() + if configLocale != "" { + if locale := findMatchingLocale(configLocale, locales); locale != "" { + setLocale(locale) + return + } + } + + if osLocale := getLocaleIdentifierFromOS(); osLocale != "" { + if locale := findMatchingLocale(osLocale, locales); locale != "" { + setLocale(locale) + return + } + } + + setLocale("en") +} diff --git a/internal/i18n/locale.go b/internal/locales/locale.go similarity index 93% rename from internal/i18n/locale.go rename to internal/locales/locale.go index 35a43e42e03..646b44059f7 100644 --- a/internal/i18n/locale.go +++ b/internal/locales/locale.go @@ -13,24 +13,19 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package i18n +package locales import ( "embed" "strings" + "github.com/arduino/arduino-cli/internal/i18n" "github.com/leonelquinteros/gotext" ) -var po *gotext.Po - //go:embed data/*.po var contents embed.FS -func init() { - po = gotext.NewPo() -} - func supportedLocales() []string { var locales []string files, err := contents.ReadDir("data") @@ -75,6 +70,7 @@ func setLocale(locale string) { if err != nil { panic("Error reading embedded i18n data: " + err.Error()) } - po = gotext.NewPo() - po.Parse(poFile) + dict := gotext.NewPo() + dict.Parse(poFile) + i18n.SetLocale(dict) } diff --git a/internal/i18n/locale_test.go b/internal/locales/locale_test.go similarity index 98% rename from internal/i18n/locale_test.go rename to internal/locales/locale_test.go index 6212258e8f8..dc0ff7ad897 100644 --- a/internal/i18n/locale_test.go +++ b/internal/locales/locale_test.go @@ -13,7 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -package i18n +package locales import ( "testing" diff --git a/main.go b/main.go index 84896ac19fe..0ead329254a 100644 --- a/main.go +++ b/main.go @@ -27,6 +27,7 @@ import ( "github.com/arduino/arduino-cli/internal/cli/configuration" "github.com/arduino/arduino-cli/internal/cli/feedback" "github.com/arduino/arduino-cli/internal/i18n" + "github.com/arduino/arduino-cli/internal/locales" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-paths-helper" "github.com/sirupsen/logrus" @@ -67,7 +68,7 @@ func main() { config := resp.GetConfiguration() // Setup i18n - i18n.Init(config.GetLocale()) + locales.Init(config.GetLocale()) // Setup command line parser with the server and settings arduinoCmd := cli.NewCommand(srv) From ea29e0290007df0b02f37d28b678827a7b625afa Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 29 Nov 2024 11:59:47 +0100 Subject: [PATCH 6/6] updated doc --- docs/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 3d801613a01..7f615230da6 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -303,7 +303,7 @@ package main import ( "fmt" - "github.com/arduino/arduino-cli/i18n" + "github.com/arduino/arduino-cli/internal/i18n" ) func main() {