Unverified Commit 4b2a32be authored by Cristian Maglie's avatar Cristian Maglie Committed by GitHub

[skip-changelog] refactor: Made `command` functions to access PackageManager...

[skip-changelog] refactor: Made `command` functions to access PackageManager unavailable from public API (#2335)

* Let instance commands require an *rpc.Instance

Removed the shorthand of the InstanceCommand interface.
This makes the API more coherent among the `commands` instance handling.

* Moved 'command' package's instances functions inside internal package

This change highlights the incorrect PackageManager access in 'cli'
package. Now those are errors:

package github.com/arduino/arduino-cli
	imports github.com/arduino/arduino-cli/internal/cli
	imports github.com/arduino/arduino-cli/internal/cli/board
	imports github.com/arduino/arduino-cli/internal/cli/arguments
	internal/cli/arguments/completion.go:23:2: use of internal package github.com/arduino/arduino-cli/commands/internal/instances not allowed
package github.com/arduino/arduino-cli
	imports github.com/arduino/arduino-cli/internal/cli
	imports github.com/arduino/arduino-cli/internal/cli/board
	imports github.com/arduino/arduino-cli/internal/cli/arguments
	internal/cli/arguments/port.go:24:2: use of internal package github.com/arduino/arduino-cli/commands/internal/instances not allowed

* Made CoreInstance private

* Inlined coreInstancesContainer singleton methods

* Removed all wrong accesses to package Explorer

* Replaced DiscoveryManager.Watch with equivalent gRPC BoardListWatch call

* Replaced direct access to PackageManager to get discovery protocols

Previously the function GetConnectedBoards() counter-intuitively
returned a list of port address. Now it has been reneamed
GetAvailablePorts() and returns the full Port object that is mapped into
an array of Addresses or into an array of Prorocols based on the
auto-completion request.
parent 1e51cdc5
......@@ -21,14 +21,14 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/utils"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// Details returns all details for a board including tools and HW identifiers.
// This command basically gather al the information and translates it into the required grpc struct properties
func Details(ctx context.Context, req *rpc.BoardDetailsRequest) (*rpc.BoardDetailsResponse, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -31,7 +31,7 @@ import (
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/arduino/discovery"
"github.com/arduino/arduino-cli/arduino/httpclient"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
"github.com/arduino/arduino-cli/internal/inventory"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/go-properties-orderedmap"
......@@ -203,7 +203,7 @@ func identify(pme *packagemanager.Explorer, port *discovery.Port) ([]*rpc.BoardL
// In case of errors partial results from discoveries that didn't fail
// are returned.
func List(req *rpc.BoardListRequest) (r []*rpc.DetectedPort, discoveryStartErrors []error, e error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, nil, &arduino.InvalidInstanceError{}
}
......@@ -258,7 +258,7 @@ func hasMatchingBoard(b *rpc.DetectedPort, fqbnFilter *cores.FQBN) bool {
// Watch returns a channel that receives boards connection and disconnection events.
func Watch(ctx context.Context, req *rpc.BoardListWatchRequest) (<-chan *rpc.BoardListWatchResponse, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -23,13 +23,13 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/utils"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// ListAll FIXMEDOC
func ListAll(ctx context.Context, req *rpc.BoardListAllRequest) (*rpc.BoardListAllResponse, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -22,7 +22,7 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/utils"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
......@@ -31,7 +31,7 @@ import (
// installed. Note that platforms that are not installed don't include boards' FQBNs.
// If no search argument is used all boards are returned.
func Search(ctx context.Context, req *rpc.BoardSearchRequest) (*rpc.BoardSearchResponse, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -30,7 +30,7 @@ import (
"github.com/arduino/arduino-cli/arduino/sketch"
"github.com/arduino/arduino-cli/arduino/utils"
"github.com/arduino/arduino-cli/buildcache"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
"github.com/arduino/arduino-cli/configuration"
"github.com/arduino/arduino-cli/i18n"
"github.com/arduino/arduino-cli/internal/inventory"
......@@ -57,13 +57,13 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream
exportBinaries = reqExportBinaries.Value
}
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
defer release()
lm := commands.GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
if lm == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -21,6 +21,7 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
"github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
......@@ -29,7 +30,7 @@ var tr = i18n.Tr
// PlatformDownload FIXMEDOC
func PlatformDownload(ctx context.Context, req *rpc.PlatformDownloadRequest, downloadCB rpc.DownloadProgressCB) (*rpc.PlatformDownloadResponse, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -22,13 +22,14 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// PlatformInstall FIXMEDOC
func PlatformInstall(ctx context.Context, req *rpc.PlatformInstallRequest, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) (*rpc.PlatformInstallResponse, error) {
install := func() error {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return &arduino.InvalidInstanceError{}
}
......
......@@ -22,13 +22,14 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// PlatformList returns a list of installed platforms, optionally filtered by
// those requiring an update.
func PlatformList(req *rpc.PlatformListRequest) (*rpc.PlatformListResponse, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -24,12 +24,13 @@ import (
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/utils"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// PlatformSearch FIXMEDOC
func PlatformSearch(req *rpc.PlatformSearchRequest) (*rpc.PlatformSearchResponse, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -21,6 +21,7 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
......@@ -37,7 +38,7 @@ func PlatformUninstall(ctx context.Context, req *rpc.PlatformUninstallRequest, t
// platformUninstall is the implementation of platform unistaller
func platformUninstall(ctx context.Context, req *rpc.PlatformUninstallRequest, taskCB rpc.TaskProgressCB) error {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return &arduino.InvalidInstanceError{}
}
......
......@@ -18,18 +18,18 @@ package core
import (
"context"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// PlatformUpgrade FIXMEDOC
func PlatformUpgrade(ctx context.Context, req *rpc.PlatformUpgradeRequest, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) (*rpc.PlatformUpgradeResponse, error) {
upgrade := func() (*cores.PlatformRelease, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -26,7 +26,7 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
"github.com/arduino/arduino-cli/executils"
"github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
......@@ -45,7 +45,7 @@ var tr = i18n.Tr
func Debug(ctx context.Context, req *rpc.GetDebugConfigRequest, inStream io.Reader, out io.Writer, interrupt <-chan os.Signal) (*rpc.DebugResponse, error) {
// Get debugging command line to run debugger
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -25,7 +25,7 @@ import (
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/arduino/sketch"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/go-paths-helper"
"github.com/arduino/go-properties-orderedmap"
......@@ -35,7 +35,7 @@ import (
// GetDebugConfig returns metadata to start debugging with the specified board
func GetDebugConfig(ctx context.Context, req *rpc.GetDebugConfigRequest) (*rpc.GetDebugConfigResponse, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -21,7 +21,6 @@ import (
"net/url"
"path/filepath"
"strings"
"sync"
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores"
......@@ -34,10 +33,10 @@ import (
"github.com/arduino/arduino-cli/arduino/resources"
"github.com/arduino/arduino-cli/arduino/sketch"
"github.com/arduino/arduino-cli/arduino/utils"
"github.com/arduino/arduino-cli/commands/internal/instances"
"github.com/arduino/arduino-cli/configuration"
"github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/arduino-cli/version"
paths "github.com/arduino/go-paths-helper"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
......@@ -46,90 +45,6 @@ import (
var tr = i18n.Tr
// CoreInstance is an instance of the Arduino Core Services. The user can
// instantiate as many as needed by providing a different configuration
// for each one.
type CoreInstance struct {
pm *packagemanager.PackageManager
lm *librariesmanager.LibrariesManager
}
// coreInstancesContainer has methods to add an remove instances atomically.
type coreInstancesContainer struct {
instances map[int32]*CoreInstance
instancesCount int32
instancesMux sync.Mutex
}
// instances contains all the running Arduino Core Services instances
var instances = &coreInstancesContainer{
instances: map[int32]*CoreInstance{},
instancesCount: 1,
}
// GetInstance returns a CoreInstance for the given ID, or nil if ID
// doesn't exist
func (c *coreInstancesContainer) GetInstance(id int32) *CoreInstance {
c.instancesMux.Lock()
defer c.instancesMux.Unlock()
return c.instances[id]
}
// AddAndAssignID saves the CoreInstance and assigns a unique ID to
// retrieve it later
func (c *coreInstancesContainer) AddAndAssignID(i *CoreInstance) int32 {
c.instancesMux.Lock()
defer c.instancesMux.Unlock()
id := c.instancesCount
c.instances[id] = i
c.instancesCount++
return id
}
// RemoveID removes the CoreInstance referenced by id. Returns true
// if the operation is successful, or false if the CoreInstance does
// not exist
func (c *coreInstancesContainer) RemoveID(id int32) bool {
c.instancesMux.Lock()
defer c.instancesMux.Unlock()
if _, ok := c.instances[id]; !ok {
return false
}
delete(c.instances, id)
return true
}
// GetPackageManager returns a PackageManager. If the package manager is not found
// (because the instance is invalid or has been destroyed), nil is returned.
// Deprecated: use GetPackageManagerExplorer instead.
func GetPackageManager(instance rpc.InstanceCommand) *packagemanager.PackageManager {
i := instances.GetInstance(instance.GetInstance().GetId())
if i == nil {
return nil
}
return i.pm
}
// GetPackageManagerExplorer returns a new package manager Explorer. The
// explorer holds a read lock on the underlying PackageManager and it should
// be released by calling the returned "release" function.
func GetPackageManagerExplorer(req rpc.InstanceCommand) (explorer *packagemanager.Explorer, release func()) {
pm := GetPackageManager(req)
if pm == nil {
return nil, nil
}
return pm.NewExplorer()
}
// GetLibraryManager returns the library manager for the given instance.
func GetLibraryManager(req rpc.InstanceCommand) *librariesmanager.LibrariesManager {
i := instances.GetInstance(req.GetInstance().GetId())
if i == nil {
return nil
}
return i.lm
}
func installTool(pm *packagemanager.PackageManager, tool *cores.ToolRelease, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error {
pme, release := pm.NewExplorer()
defer release()
......@@ -146,50 +61,11 @@ func installTool(pm *packagemanager.PackageManager, tool *cores.ToolRelease, dow
// Create a new CoreInstance ready to be initialized, supporting directories are also created.
func Create(req *rpc.CreateRequest, extraUserAgent ...string) (*rpc.CreateResponse, error) {
instance := &CoreInstance{}
// Setup downloads directory
downloadsDir := configuration.DownloadsDir(configuration.Settings)
if downloadsDir.NotExist() {
err := downloadsDir.MkdirAll()
if err != nil {
return nil, &arduino.PermissionDeniedError{Message: tr("Failed to create downloads directory"), Cause: err}
}
}
// Setup data directory
dataDir := configuration.DataDir(configuration.Settings)
packagesDir := configuration.PackagesDir(configuration.Settings)
if packagesDir.NotExist() {
err := packagesDir.MkdirAll()
if err != nil {
return nil, &arduino.PermissionDeniedError{Message: tr("Failed to create data directory"), Cause: err}
}
}
// Create package manager
userAgent := "arduino-cli/" + version.VersionInfo.VersionString
for _, ua := range extraUserAgent {
userAgent += " " + ua
inst, err := instances.Create(extraUserAgent...)
if err != nil {
return nil, err
}
instance.pm = packagemanager.NewBuilder(
dataDir,
configuration.PackagesDir(configuration.Settings),
downloadsDir,
dataDir.Join("tmp"),
userAgent,
).Build()
instance.lm = librariesmanager.NewLibraryManager(
dataDir,
downloadsDir,
)
// Save instance
instanceID := instances.AddAndAssignID(instance)
return &rpc.CreateResponse{
Instance: &rpc.Instance{Id: instanceID},
}, nil
return &rpc.CreateResponse{Instance: inst}, nil
}
// Init loads installed libraries and Platforms in CoreInstance with specified ID,
......@@ -205,8 +81,8 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
if reqInst == nil {
return &arduino.InvalidInstanceError{}
}
instance := instances.GetInstance(reqInst.GetId())
if instance == nil {
instance := req.GetInstance()
if !instances.IsValid(instance) {
return &arduino.InvalidInstanceError{}
}
......@@ -295,7 +171,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
// after reinitializing an instance after installing or uninstalling a core.
// If this is not done the information of the uninstall core is kept in memory,
// even if it should not.
pmb, commitPackageManager := instance.pm.NewBuilder()
pmb, commitPackageManager := instances.GetPackageManager(instance).NewBuilder()
// Load packages index
for _, URL := range allPackageIndexUrls {
......@@ -390,7 +266,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
commitPackageManager()
}
pme, release := instance.pm.NewExplorer()
pme, release := instances.GetPackageManagerExplorer(instance)
defer release()
for _, err := range pme.LoadDiscoveries() {
......@@ -403,7 +279,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
pme.IndexDir,
pme.DownloadDir,
)
instance.lm = lm
_ = instances.SetLibraryManager(instance, lm) // should never fail
// Load libraries
for _, pack := range pme.GetPackages() {
......@@ -485,7 +361,7 @@ func Init(req *rpc.InitRequest, responseCallback func(r *rpc.InitResponse)) erro
// Destroy FIXMEDOC
func Destroy(ctx context.Context, req *rpc.DestroyRequest) (*rpc.DestroyResponse, error) {
if ok := instances.RemoveID(req.GetInstance().GetId()); !ok {
if ok := instances.Delete(req.GetInstance()); !ok {
return nil, &arduino.InvalidInstanceError{}
}
return &rpc.DestroyResponse{}, nil
......@@ -494,7 +370,7 @@ func Destroy(ctx context.Context, req *rpc.DestroyRequest) (*rpc.DestroyResponse
// UpdateLibrariesIndex updates the library_index.json
func UpdateLibrariesIndex(ctx context.Context, req *rpc.UpdateLibrariesIndexRequest, downloadCB rpc.DownloadProgressCB) error {
logrus.Info("Updating libraries index")
lm := GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
if lm == nil {
return &arduino.InvalidInstanceError{}
}
......@@ -523,7 +399,7 @@ func UpdateLibrariesIndex(ctx context.Context, req *rpc.UpdateLibrariesIndexRequ
// UpdateIndex FIXMEDOC
func UpdateIndex(ctx context.Context, req *rpc.UpdateIndexRequest, downloadCB rpc.DownloadProgressCB) error {
if instances.GetInstance(req.GetInstance().GetId()) == nil {
if !instances.IsValid(req.GetInstance()) {
return &arduino.InvalidInstanceError{}
}
......
package instances
import (
"sync"
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/arduino/libraries/librariesmanager"
"github.com/arduino/arduino-cli/configuration"
"github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/arduino-cli/version"
)
var tr = i18n.Tr
// coreInstance is an instance of the Arduino Core Services. The user can
// instantiate as many as needed by providing a different configuration
// for each one.
type coreInstance struct {
pm *packagemanager.PackageManager
lm *librariesmanager.LibrariesManager
}
// instances contains all the running Arduino Core Services instances
var instances = map[int32]*coreInstance{}
var instancesCount int32 = 1
var instancesMux sync.Mutex
// GetPackageManager returns a PackageManager. If the package manager is not found
// (because the instance is invalid or has been destroyed), nil is returned.
// Deprecated: use GetPackageManagerExplorer instead.
func GetPackageManager(inst *rpc.Instance) *packagemanager.PackageManager {
instancesMux.Lock()
i := instances[inst.GetId()]
instancesMux.Unlock()
if i == nil {
return nil
}
return i.pm
}
// GetPackageManagerExplorer returns a new package manager Explorer. The
// explorer holds a read lock on the underlying PackageManager and it should
// be released by calling the returned "release" function.
func GetPackageManagerExplorer(req *rpc.Instance) (explorer *packagemanager.Explorer, release func()) {
pm := GetPackageManager(req)
if pm == nil {
return nil, nil
}
return pm.NewExplorer()
}
// GetLibraryManager returns the library manager for the given instance.
func GetLibraryManager(inst *rpc.Instance) *librariesmanager.LibrariesManager {
instancesMux.Lock()
i := instances[inst.GetId()]
instancesMux.Unlock()
if i == nil {
return nil
}
return i.lm
}
// SetLibraryManager sets the library manager for the given instance.
func SetLibraryManager(inst *rpc.Instance, lm *librariesmanager.LibrariesManager) bool {
instancesMux.Lock()
i := instances[inst.GetId()]
instancesMux.Unlock()
if i == nil {
return false
}
i.lm = lm
return true
}
// Create a new *rpc.Instance ready to be initialized, supporting directories are also created.
func Create(extraUserAgent ...string) (*rpc.Instance, error) {
instance := &coreInstance{}
// Setup downloads directory
downloadsDir := configuration.DownloadsDir(configuration.Settings)
if downloadsDir.NotExist() {
err := downloadsDir.MkdirAll()
if err != nil {
return nil, &arduino.PermissionDeniedError{Message: tr("Failed to create downloads directory"), Cause: err}
}
}
// Setup data directory
dataDir := configuration.DataDir(configuration.Settings)
packagesDir := configuration.PackagesDir(configuration.Settings)
if packagesDir.NotExist() {
err := packagesDir.MkdirAll()
if err != nil {
return nil, &arduino.PermissionDeniedError{Message: tr("Failed to create data directory"), Cause: err}
}
}
// Create package manager
userAgent := "arduino-cli/" + version.VersionInfo.VersionString
for _, ua := range extraUserAgent {
userAgent += " " + ua
}
instance.pm = packagemanager.NewBuilder(
dataDir,
configuration.PackagesDir(configuration.Settings),
downloadsDir,
dataDir.Join("tmp"),
userAgent,
).Build()
instance.lm = librariesmanager.NewLibraryManager(
dataDir,
downloadsDir,
)
// Save instance
instancesMux.Lock()
id := instancesCount
instances[id] = instance
instancesCount++
instancesMux.Unlock()
return &rpc.Instance{Id: id}, nil
}
// IsValid returns true if the given instance is valid.
func IsValid(inst *rpc.Instance) bool {
instancesMux.Lock()
i := instances[inst.GetId()]
instancesMux.Unlock()
return i != nil
}
// Delete removes an instance.
func Delete(inst *rpc.Instance) bool {
instancesMux.Lock()
defer instancesMux.Unlock()
if _, ok := instances[inst.GetId()]; !ok {
return false
}
delete(instances, inst.GetId())
return true
}
......@@ -22,7 +22,7 @@ import (
"github.com/arduino/arduino-cli/arduino/httpclient"
"github.com/arduino/arduino-cli/arduino/libraries/librariesindex"
"github.com/arduino/arduino-cli/arduino/libraries/librariesmanager"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
"github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/sirupsen/logrus"
......@@ -35,7 +35,7 @@ var tr = i18n.Tr
func LibraryDownload(ctx context.Context, req *rpc.LibraryDownloadRequest, downloadCB rpc.DownloadProgressCB) (*rpc.LibraryDownloadResponse, error) {
logrus.Info("Executing `arduino-cli lib download`")
lm := commands.GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
if lm == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -25,6 +25,7 @@ import (
"github.com/arduino/arduino-cli/arduino/libraries/librariesindex"
"github.com/arduino/arduino-cli/arduino/libraries/librariesmanager"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/go-paths-helper"
"github.com/sirupsen/logrus"
......@@ -32,7 +33,7 @@ import (
// LibraryInstall resolves the library dependencies, then downloads and installs the libraries into the install location.
func LibraryInstall(ctx context.Context, req *rpc.LibraryInstallRequest, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error {
lm := commands.GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
if lm == nil {
return &arduino.InvalidInstanceError{}
}
......@@ -143,7 +144,7 @@ func installLibrary(lm *librariesmanager.LibrariesManager, libRelease *libraries
// ZipLibraryInstall FIXMEDOC
func ZipLibraryInstall(ctx context.Context, req *rpc.ZipLibraryInstallRequest, taskCB rpc.TaskProgressCB) error {
lm := commands.GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
if err := lm.InstallZipLib(ctx, paths.New(req.Path), req.Overwrite); err != nil {
return &arduino.FailedLibraryInstallError{Cause: err}
}
......@@ -153,7 +154,7 @@ func ZipLibraryInstall(ctx context.Context, req *rpc.ZipLibraryInstallRequest, t
// GitLibraryInstall FIXMEDOC
func GitLibraryInstall(ctx context.Context, req *rpc.GitLibraryInstallRequest, taskCB rpc.TaskProgressCB) error {
lm := commands.GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
if err := lm.InstallGitLib(req.Url, req.Overwrite); err != nil {
return &arduino.FailedLibraryInstallError{Cause: err}
}
......
......@@ -25,7 +25,7 @@ import (
"github.com/arduino/arduino-cli/arduino/libraries/librariesindex"
"github.com/arduino/arduino-cli/arduino/libraries/librariesmanager"
"github.com/arduino/arduino-cli/arduino/libraries/librariesresolver"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
......@@ -36,13 +36,13 @@ type installedLib struct {
// LibraryList FIXMEDOC
func LibraryList(ctx context.Context, req *rpc.LibraryListRequest) (*rpc.LibraryListResponse, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
defer release()
lm := commands.GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
if lm == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -22,13 +22,13 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/libraries"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// LibraryResolveDependencies FIXMEDOC
func LibraryResolveDependencies(ctx context.Context, req *rpc.LibraryResolveDependenciesRequest) (*rpc.LibraryResolveDependenciesResponse, error) {
lm := commands.GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
if lm == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -24,14 +24,14 @@ import (
"github.com/arduino/arduino-cli/arduino/libraries/librariesindex"
"github.com/arduino/arduino-cli/arduino/libraries/librariesmanager"
"github.com/arduino/arduino-cli/arduino/utils"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
semver "go.bug.st/relaxed-semver"
)
// LibrarySearch FIXMEDOC
func LibrarySearch(ctx context.Context, req *rpc.LibrarySearchRequest) (*rpc.LibrarySearchResponse, error) {
lm := commands.GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
if lm == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -20,14 +20,14 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/libraries"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/go-paths-helper"
)
// LibraryUninstall FIXMEDOC
func LibraryUninstall(ctx context.Context, req *rpc.LibraryUninstallRequest, taskCB rpc.TaskProgressCB) error {
lm := commands.GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
ref, err := createLibIndexReference(lm, req)
if err != nil {
return &arduino.InvalidLibraryError{Cause: err}
......
......@@ -20,12 +20,13 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// LibraryUpgradeAll upgrades all the available libraries
func LibraryUpgradeAll(req *rpc.LibraryUpgradeAllRequest, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error {
lm := commands.GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
if lm == nil {
return &arduino.InvalidInstanceError{}
}
......@@ -43,7 +44,7 @@ func LibraryUpgradeAll(req *rpc.LibraryUpgradeAllRequest, downloadCB rpc.Downloa
// LibraryUpgrade upgrades a library
func LibraryUpgrade(ctx context.Context, req *rpc.LibraryUpgradeRequest, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error {
lm := commands.GetLibraryManager(req)
lm := instances.GetLibraryManager(req.GetInstance())
if lm == nil {
return &arduino.InvalidInstanceError{}
}
......
......@@ -24,7 +24,7 @@ import (
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
pluggableMonitor "github.com/arduino/arduino-cli/arduino/monitor"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
"github.com/arduino/arduino-cli/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/go-properties-orderedmap"
......@@ -61,7 +61,7 @@ func (p *PortProxy) Close() error {
// Monitor opens a communication port. It returns a PortProxy to communicate with the port and a PortDescriptor
// that describes the available configuration settings.
func Monitor(ctx context.Context, req *rpc.MonitorRequest) (*PortProxy, *pluggableMonitor.PortDescriptor, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, nil, &arduino.InvalidInstanceError{}
}
......
......@@ -20,13 +20,13 @@ import (
"github.com/arduino/arduino-cli/arduino"
pluggableMonitor "github.com/arduino/arduino-cli/arduino/monitor"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// EnumerateMonitorPortSettings returns a description of the configuration settings of a monitor port
func EnumerateMonitorPortSettings(ctx context.Context, req *rpc.EnumerateMonitorPortSettingsRequest) (*rpc.EnumerateMonitorPortSettingsResponse, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -20,7 +20,7 @@ import (
"io"
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/sirupsen/logrus"
)
......@@ -33,7 +33,7 @@ func BurnBootloader(ctx context.Context, req *rpc.BurnBootloaderRequest, outStre
WithField("programmer", req.GetProgrammer()).
Trace("BurnBootloader started", req.GetFqbn())
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -20,13 +20,13 @@ import (
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)
// ListProgrammersAvailableForUpload FIXMEDOC
func ListProgrammersAvailableForUpload(ctx context.Context, req *rpc.ListProgrammersAvailableForUploadRequest) (*rpc.ListProgrammersAvailableForUploadResponse, error) {
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -30,7 +30,7 @@ import (
"github.com/arduino/arduino-cli/arduino/globals"
"github.com/arduino/arduino-cli/arduino/serialutils"
"github.com/arduino/arduino-cli/arduino/sketch"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/internal/instances"
"github.com/arduino/arduino-cli/executils"
"github.com/arduino/arduino-cli/i18n"
f "github.com/arduino/arduino-cli/internal/algorithms"
......@@ -50,7 +50,7 @@ func SupportedUserFields(ctx context.Context, req *rpc.SupportedUserFieldsReques
return nil, &arduino.MissingPortProtocolError{}
}
pme, release := commands.GetPackageManagerExplorer(req)
pme, release := instances.GetPackageManagerExplorer(req.GetInstance())
defer release()
if pme == nil {
......@@ -137,7 +137,7 @@ func Upload(ctx context.Context, req *rpc.UploadRequest, outStream io.Writer, er
return nil, &arduino.CantOpenSketchError{Cause: err}
}
pme, pmeRelease := commands.GetPackageManagerExplorer(req)
pme, pmeRelease := instances.GetPackageManagerExplorer(req.GetInstance())
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
......
......@@ -18,7 +18,6 @@ package arguments
import (
"context"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/board"
"github.com/arduino/arduino-cli/commands/core"
"github.com/arduino/arduino-cli/commands/lib"
......@@ -46,41 +45,6 @@ func GetInstalledBoards() []string {
return res
}
// GetInstalledProtocols is an helper function useful to autocomplete.
// It returns a list of protocols available based on the installed boards
func GetInstalledProtocols() []string {
inst := instance.CreateAndInit()
// FIXME: We must not access PackageManager directly here but use one of the commands.* functions
pme, release := commands.GetPackageManagerExplorer(&rpc.BoardListAllRequest{Instance: inst})
if pme == nil {
return nil // should never happen...
}
defer release()
boards := pme.InstalledBoards()
installedProtocols := make(map[string]struct{})
for _, board := range boards {
for _, protocol := range board.Properties.SubTree("upload.tool").FirstLevelKeys() {
if protocol == "default" {
// default is used as fallback when trying to upload to a board
// using a protocol not defined for it, it's useless showing it
// in autocompletion
continue
}
installedProtocols[protocol] = struct{}{}
}
}
res := make([]string, len(installedProtocols))
i := 0
for k := range installedProtocols {
res[i] = k
i++
}
return res
}
// GetInstalledProgrammers is an helper function useful to autocomplete.
// It returns a list of programmers available based on the installed boards
func GetInstalledProgrammers() []string {
......@@ -94,13 +58,6 @@ func GetInstalledProgrammers() []string {
}
list, _ := board.ListAll(context.Background(), listAllReq)
// FIXME: We must not access PackageManager directly here but use one of the commands.* functions
pme, release := commands.GetPackageManagerExplorer(listAllReq)
if pme == nil {
return nil // should never happen...
}
defer release()
installedProgrammers := make(map[string]string)
for _, board := range list.Boards {
programmers, _ := upload.ListProgrammersAvailableForUpload(context.Background(), &rpc.ListProgrammersAvailableForUploadRequest{
......@@ -203,19 +160,19 @@ func GetInstallableLibs() []string {
return res
}
// GetConnectedBoards is an helper function useful to autocomplete.
// It returns a list of boards which are currently connected
// Obviously it does not suggests network ports because of the timeout
func GetConnectedBoards() []string {
// GetAvailablePorts is an helper function useful to autocomplete.
// It returns a list of upload port of the boards which are currently connected.
// It will not suggests network ports because the timeout is not set.
func GetAvailablePorts() []*rpc.Port {
inst := instance.CreateAndInit()
list, _, _ := board.List(&rpc.BoardListRequest{
Instance: inst,
})
var res []string
var res []*rpc.Port
// transform the data structure for the completion
for _, i := range list {
res = append(res, i.Port.Address)
res = append(res, i.Port)
}
return res
}
......@@ -16,12 +16,13 @@
package arguments
import (
"context"
"fmt"
"time"
"github.com/arduino/arduino-cli/arduino"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/board"
f "github.com/arduino/arduino-cli/internal/algorithms"
"github.com/arduino/arduino-cli/internal/cli/feedback"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/sirupsen/logrus"
......@@ -41,11 +42,11 @@ type Port struct {
func (p *Port) AddToCommand(cmd *cobra.Command) {
cmd.Flags().StringVarP(&p.address, "port", "p", "", tr("Upload port address, e.g.: COM3 or /dev/ttyACM2"))
cmd.RegisterFlagCompletionFunc("port", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return GetConnectedBoards(), cobra.ShellCompDirectiveDefault
return f.Map(GetAvailablePorts(), (*rpc.Port).GetAddress), cobra.ShellCompDirectiveDefault
})
cmd.Flags().StringVarP(&p.protocol, "protocol", "l", "", tr("Upload port protocol, e.g: serial"))
cmd.RegisterFlagCompletionFunc("protocol", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return GetInstalledProtocols(), cobra.ShellCompDirectiveDefault
return f.Map(GetAvailablePorts(), (*rpc.Port).GetProtocol), cobra.ShellCompDirectiveDefault
})
p.timeout.AddToCommand(cmd)
}
......@@ -88,30 +89,23 @@ func (p *Port) GetPort(instance *rpc.Instance, defaultAddress, defaultProtocol s
}
logrus.WithField("port", address).Tracef("Upload port")
// FIXME: We must not access PackageManager directly here but use one of the commands.* functions
pme, release := commands.GetPackageManagerExplorer(&rpc.BoardListAllRequest{Instance: instance})
if pme == nil {
return nil, &arduino.InvalidInstanceError{}
}
defer release()
dm := pme.DiscoveryManager()
watcher, err := dm.Watch()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
watcher, err := board.Watch(ctx, &rpc.BoardListWatchRequest{Instance: instance})
if err != nil {
return nil, err
}
defer watcher.Close()
deadline := time.After(p.timeout.Get())
for {
select {
case portEvent := <-watcher.Feed():
if portEvent.Type != "add" {
case portEvent := <-watcher:
if portEvent.GetEventType() != "add" {
continue
}
port := portEvent.Port
if (protocol == "" || protocol == port.Protocol) && address == port.Address {
return port.ToRPC(), nil
port := portEvent.GetPort().GetPort()
if (protocol == "" || protocol == port.GetProtocol()) && address == port.GetAddress() {
return port, nil
}
case <-deadline:
......
......@@ -216,16 +216,10 @@ func TestCoreCompletion(t *testing.T) {
require.Contains(t, string(stdout), "arduino:avr:uno")
stdout, _, _ = cli.Run("__complete", "monitor", "-b", "")
require.Contains(t, string(stdout), "arduino:avr:uno")
stdout, _, _ = cli.Run("__complete", "burn-bootloader", "-l", "")
require.Contains(t, string(stdout), "network")
stdout, _, _ = cli.Run("__complete", "compile", "-l", "")
require.Contains(t, string(stdout), "network")
stdout, _, _ = cli.Run("__complete", "debug", "-l", "")
require.Contains(t, string(stdout), "network")
stdout, _, _ = cli.Run("__complete", "upload", "-l", "")
require.Contains(t, string(stdout), "network")
stdout, _, _ = cli.Run("__complete", "monitor", "-l", "")
require.Contains(t, string(stdout), "network")
// -l/--protocol and -p/--port cannot be tested because there are
// no board connected.
stdout, _, _ = cli.Run("__complete", "burn-bootloader", "-P", "")
require.Contains(t, string(stdout), "atmel_ice")
stdout, _, _ = cli.Run("__complete", "compile", "-P", "")
......
......@@ -56,9 +56,3 @@ func (d DownloadProgressCB) End(success bool, message string) {
// TaskProgressCB is a callback to receive progress messages
type TaskProgressCB func(msg *TaskProgress)
// InstanceCommand is an interface that represents a gRPC command with
// a gRPC Instance.
type InstanceCommand interface {
GetInstance() *Instance
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment