From c1f439362c67c5afe050245cd6f1cd0331bd5a5f Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 28 Feb 2022 15:52:37 +0100 Subject: [PATCH 1/6] Updated relaxed-semver library to v0.9.0 --- .licenses/go/go.bug.st/relaxed-semver.dep.yml | 4 ++-- arduino/discovery/discovery_client/go.sum | 2 +- client_example/go.sum | 2 +- docsgen/go.mod | 2 +- docsgen/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.licenses/go/go.bug.st/relaxed-semver.dep.yml b/.licenses/go/go.bug.st/relaxed-semver.dep.yml index c4767621b5d..bc044af9547 100644 --- a/.licenses/go/go.bug.st/relaxed-semver.dep.yml +++ b/.licenses/go/go.bug.st/relaxed-semver.dep.yml @@ -1,6 +1,6 @@ --- name: go.bug.st/relaxed-semver -version: v0.0.0-20190922224835-391e10178d18 +version: v0.9.0 type: go summary: homepage: https://pkg.go.dev/go.bug.st/relaxed-semver @@ -9,7 +9,7 @@ licenses: - sources: LICENSE text: |2+ - Copyright (c) 2018, Cristian Maglie. + Copyright (c) 2018-2022, Cristian Maglie. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/arduino/discovery/discovery_client/go.sum b/arduino/discovery/discovery_client/go.sum index 712052514e9..7c7b46c136e 100644 --- a/arduino/discovery/discovery_client/go.sum +++ b/arduino/discovery/discovery_client/go.sum @@ -305,7 +305,7 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.bug.st/cleanup v1.0.0/go.mod h1:EqVmTg2IBk4znLbPD28xne3abjsJftMdqqJEjhn70bk= go.bug.st/downloader/v2 v2.1.1/go.mod h1:VZW2V1iGKV8rJL2ZEGIDzzBeKowYv34AedJz13RzVII= -go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18/go.mod h1:Cx1VqMtEhE9pIkEyUj3LVVVPkv89dgW8aCKrRPDR/uE= +go.bug.st/relaxed-semver v0.9.0/go.mod h1:ug0/W/RPYUjliE70Ghxg77RDHmPxqpo7SHV16ijss7Q= go.bug.st/serial v1.3.2/go.mod h1:jDkjqASf/qSjmaOxHSHljwUQ6eHo/ZX/bxJLQqSlvZg= go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45/go.mod h1:dRSl/CVCTf56CkXgJMDOdSwNfo2g1orOGE/gBGdvjZw= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= diff --git a/client_example/go.sum b/client_example/go.sum index 40867f1ad6d..61f91616448 100644 --- a/client_example/go.sum +++ b/client_example/go.sum @@ -288,7 +288,7 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.bug.st/cleanup v1.0.0/go.mod h1:EqVmTg2IBk4znLbPD28xne3abjsJftMdqqJEjhn70bk= go.bug.st/downloader/v2 v2.1.1/go.mod h1:VZW2V1iGKV8rJL2ZEGIDzzBeKowYv34AedJz13RzVII= -go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18/go.mod h1:Cx1VqMtEhE9pIkEyUj3LVVVPkv89dgW8aCKrRPDR/uE= +go.bug.st/relaxed-semver v0.9.0/go.mod h1:ug0/W/RPYUjliE70Ghxg77RDHmPxqpo7SHV16ijss7Q= go.bug.st/serial v1.3.2/go.mod h1:jDkjqASf/qSjmaOxHSHljwUQ6eHo/ZX/bxJLQqSlvZg= go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45/go.mod h1:dRSl/CVCTf56CkXgJMDOdSwNfo2g1orOGE/gBGdvjZw= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= diff --git a/docsgen/go.mod b/docsgen/go.mod index 8dcb292efb4..a7e60815479 100644 --- a/docsgen/go.mod +++ b/docsgen/go.mod @@ -66,7 +66,7 @@ require ( github.com/xanzy/ssh-agent v0.2.1 // indirect go.bug.st/cleanup v1.0.0 // indirect go.bug.st/downloader/v2 v2.1.1 // indirect - go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 // indirect + go.bug.st/relaxed-semver v0.9.0 // indirect go.bug.st/serial v1.3.2 // indirect go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45 // indirect golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect diff --git a/docsgen/go.sum b/docsgen/go.sum index 7226e9660d5..7b9a65b6f4d 100644 --- a/docsgen/go.sum +++ b/docsgen/go.sum @@ -359,8 +359,8 @@ go.bug.st/cleanup v1.0.0 h1:XVj1HZxkBXeq3gMT7ijWUpHyIC1j8XAoNSyQ06CskgA= go.bug.st/cleanup v1.0.0/go.mod h1:EqVmTg2IBk4znLbPD28xne3abjsJftMdqqJEjhn70bk= go.bug.st/downloader/v2 v2.1.1 h1:nyqbUizo3E2IxCCm4YFac4FtSqqFpqWP+Aae5GCMuw4= go.bug.st/downloader/v2 v2.1.1/go.mod h1:VZW2V1iGKV8rJL2ZEGIDzzBeKowYv34AedJz13RzVII= -go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 h1:F1qxtaFuewctYc/SsHRn+Q7Dtwi+yJGPgVq8YLtQz98= -go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18/go.mod h1:Cx1VqMtEhE9pIkEyUj3LVVVPkv89dgW8aCKrRPDR/uE= +go.bug.st/relaxed-semver v0.9.0 h1:qt0T8W70VCurvsbxRK25fQwiTOFjkzwC/fDOpyPnchQ= +go.bug.st/relaxed-semver v0.9.0/go.mod h1:ug0/W/RPYUjliE70Ghxg77RDHmPxqpo7SHV16ijss7Q= go.bug.st/serial v1.3.2 h1:6BFZZd/wngoL5PPYYTrFUounF54SIkykHpT98eq6zvk= go.bug.st/serial v1.3.2/go.mod h1:jDkjqASf/qSjmaOxHSHljwUQ6eHo/ZX/bxJLQqSlvZg= go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45 h1:mACY1anK6HNCZtm/DK2Rf2ZPHggVqeB0+7rY9Gl6wyI= diff --git a/go.mod b/go.mod index a94e290494c..cff73354cdd 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/stretchr/testify v1.7.0 go.bug.st/cleanup v1.0.0 go.bug.st/downloader/v2 v2.1.1 - go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 + go.bug.st/relaxed-semver v0.9.0 go.bug.st/serial v1.3.2 go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45 // indirect golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 diff --git a/go.sum b/go.sum index 7226e9660d5..7b9a65b6f4d 100644 --- a/go.sum +++ b/go.sum @@ -359,8 +359,8 @@ go.bug.st/cleanup v1.0.0 h1:XVj1HZxkBXeq3gMT7ijWUpHyIC1j8XAoNSyQ06CskgA= go.bug.st/cleanup v1.0.0/go.mod h1:EqVmTg2IBk4znLbPD28xne3abjsJftMdqqJEjhn70bk= go.bug.st/downloader/v2 v2.1.1 h1:nyqbUizo3E2IxCCm4YFac4FtSqqFpqWP+Aae5GCMuw4= go.bug.st/downloader/v2 v2.1.1/go.mod h1:VZW2V1iGKV8rJL2ZEGIDzzBeKowYv34AedJz13RzVII= -go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 h1:F1qxtaFuewctYc/SsHRn+Q7Dtwi+yJGPgVq8YLtQz98= -go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18/go.mod h1:Cx1VqMtEhE9pIkEyUj3LVVVPkv89dgW8aCKrRPDR/uE= +go.bug.st/relaxed-semver v0.9.0 h1:qt0T8W70VCurvsbxRK25fQwiTOFjkzwC/fDOpyPnchQ= +go.bug.st/relaxed-semver v0.9.0/go.mod h1:ug0/W/RPYUjliE70Ghxg77RDHmPxqpo7SHV16ijss7Q= go.bug.st/serial v1.3.2 h1:6BFZZd/wngoL5PPYYTrFUounF54SIkykHpT98eq6zvk= go.bug.st/serial v1.3.2/go.mod h1:jDkjqASf/qSjmaOxHSHljwUQ6eHo/ZX/bxJLQqSlvZg= go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45 h1:mACY1anK6HNCZtm/DK2Rf2ZPHggVqeB0+7rY9Gl6wyI= From 358b84f5d3bc9cbe0a8af6bd03a61ae3334dcf81 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 31 Mar 2022 12:12:58 +0200 Subject: [PATCH 2/6] Fixed errors translations --- arduino/resources/install.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arduino/resources/install.go b/arduino/resources/install.go index cb2043aa1c7..165020250b3 100644 --- a/arduino/resources/install.go +++ b/arduino/resources/install.go @@ -34,29 +34,29 @@ import ( func (release *DownloadResource) Install(downloadDir, tempPath, destDir *paths.Path) error { // Check the integrity of the package if ok, err := release.TestLocalArchiveIntegrity(downloadDir); err != nil { - return fmt.Errorf(tr("testing local archive integrity: %s"), err) + return fmt.Errorf(tr("testing local archive integrity: %s", err)) } else if !ok { return fmt.Errorf(tr("checking local archive integrity")) } // Create a temporary dir to extract package if err := tempPath.MkdirAll(); err != nil { - return fmt.Errorf(tr("creating temp dir for extraction: %s"), err) + return fmt.Errorf(tr("creating temp dir for extraction: %s", err)) } tempDir, err := tempPath.MkTempDir("package-") if err != nil { - return fmt.Errorf(tr("creating temp dir for extraction: %s"), err) + return fmt.Errorf(tr("creating temp dir for extraction: %s", err)) } defer tempDir.RemoveAll() // Obtain the archive path and open it archivePath, err := release.ArchivePath(downloadDir) if err != nil { - return fmt.Errorf(tr("getting archive path: %s"), err) + return fmt.Errorf(tr("getting archive path: %s", err)) } file, err := os.Open(archivePath.String()) if err != nil { - return fmt.Errorf(tr("opening archive file: %s"), err) + return fmt.Errorf(tr("opening archive file: %s", err)) } defer file.Close() @@ -64,13 +64,13 @@ func (release *DownloadResource) Install(downloadDir, tempPath, destDir *paths.P ctx, cancel := cleanup.InterruptableContext(context.Background()) defer cancel() if err := extract.Archive(ctx, file, tempDir.String(), nil); err != nil { - return fmt.Errorf(tr("extracting archive: %s"), err) + return fmt.Errorf(tr("extracting archive: %s", err)) } // Check package content and find package root dir root, err := findPackageRoot(tempDir) if err != nil { - return fmt.Errorf(tr("searching package root dir: %s"), err) + return fmt.Errorf(tr("searching package root dir: %s", err)) } // Ensure container dir exists @@ -91,7 +91,7 @@ func (release *DownloadResource) Install(downloadDir, tempPath, destDir *paths.P // Move/rename the extracted root directory in the destination directory if err := root.Rename(destDir); err != nil { - return fmt.Errorf(tr("moving extracted archive to destination dir: %s"), err) + return fmt.Errorf(tr("moving extracted archive to destination dir: %s", err)) } // TODO @@ -115,7 +115,7 @@ func IsDirEmpty(path *paths.Path) (bool, error) { func findPackageRoot(parent *paths.Path) (*paths.Path, error) { files, err := parent.ReadDir() if err != nil { - return nil, fmt.Errorf(tr("reading package root dir: %s"), err) + return nil, fmt.Errorf(tr("reading package root dir: %s", err)) } var root *paths.Path for _, file := range files { @@ -125,7 +125,7 @@ func findPackageRoot(parent *paths.Path) (*paths.Path, error) { if root == nil { root = file } else { - return nil, fmt.Errorf(tr("no unique root dir in archive, found '%[1]s' and '%[2]s'"), root, file) + return nil, fmt.Errorf(tr("no unique root dir in archive, found '%[1]s' and '%[2]s'", root, file)) } } if root == nil { From 04a683f774bb53367224e429b5129c66a1852804 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 4 Mar 2022 16:03:46 +0100 Subject: [PATCH 3/6] Make architecture explicit in loadPlatform --- arduino/cores/packagemanager/loader.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arduino/cores/packagemanager/loader.go b/arduino/cores/packagemanager/loader.go index 16bee8d7fd3..d45451c1dc1 100644 --- a/arduino/cores/packagemanager/loader.go +++ b/arduino/cores/packagemanager/loader.go @@ -157,11 +157,13 @@ func (pm *PackageManager) loadPlatforms(targetPackage *cores.Package, packageDir // Filter out directories like .git and similar things platformsDirs.FilterOutPrefix(".") for _, platformPath := range platformsDirs { + targetArchitecture := platformPath.Base() + // Tools are not a platform - if platformPath.Base() == "tools" { + if targetArchitecture == "tools" { continue } - if err := pm.loadPlatform(targetPackage, platformPath); err != nil { + if err := pm.loadPlatform(targetPackage, targetArchitecture, platformPath); err != nil { merr = append(merr, err) } } @@ -172,14 +174,12 @@ func (pm *PackageManager) loadPlatforms(targetPackage *cores.Package, packageDir // loadPlatform loads a single platform and all its installed releases given a platformPath. // platformPath must be a directory. // Returns a gRPC Status error in case of failures. -func (pm *PackageManager) loadPlatform(targetPackage *cores.Package, platformPath *paths.Path) error { +func (pm *PackageManager) loadPlatform(targetPackage *cores.Package, architecture string, platformPath *paths.Path) error { // This is not a platform if platformPath.IsNotDir() { return errors.New(tr("path is not a platform directory: %s", platformPath)) } - architecture := platformPath.Base() - // There are two possible platform directory structures: // - ARCHITECTURE/boards.txt // - ARCHITECTURE/VERSION/boards.txt From ac5bc83053d83b57e39957f319501ccfff815cd7 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 7 Mar 2022 17:12:20 +0100 Subject: [PATCH 4/6] Extracted subrotuine loadToolReleaseFromDirectory --- arduino/cores/packagemanager/loader.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/arduino/cores/packagemanager/loader.go b/arduino/cores/packagemanager/loader.go index d45451c1dc1..16b4de8acb1 100644 --- a/arduino/cores/packagemanager/loader.go +++ b/arduino/cores/packagemanager/loader.go @@ -618,12 +618,8 @@ func (pm *PackageManager) loadToolReleasesFromTool(tool *cores.Tool, toolPath *p toolVersions.FilterDirs() toolVersions.FilterOutHiddenFiles() for _, versionPath := range toolVersions { - if toolReleasePath, err := versionPath.Abs(); err == nil { - version := semver.ParseRelaxed(versionPath.Base()) - release := tool.GetOrCreateRelease(version) - release.InstallDir = toolReleasePath - pm.Log.WithField("tool", release).Infof("Loaded tool") - } else { + version := semver.ParseRelaxed(versionPath.Base()) + if err := pm.loadToolReleaseFromDirectory(tool, version, versionPath); err != nil { return err } } @@ -631,6 +627,19 @@ func (pm *PackageManager) loadToolReleasesFromTool(tool *cores.Tool, toolPath *p return nil } +func (pm *PackageManager) loadToolReleaseFromDirectory(tool *cores.Tool, version *semver.RelaxedVersion, toolReleasePath *paths.Path) error { + if absToolReleasePath, err := toolReleasePath.Abs(); err != nil { + return errors.New(tr("error opening %s", absToolReleasePath)) + } else if !absToolReleasePath.IsDir() { + return errors.New(tr("%s is not a directory", absToolReleasePath)) + } else { + toolRelease := tool.GetOrCreateRelease(version) + toolRelease.InstallDir = absToolReleasePath + pm.Log.WithField("tool", toolRelease).Infof("Loaded tool") + return nil + } +} + // LoadToolsFromBundleDirectories FIXMEDOC func (pm *PackageManager) LoadToolsFromBundleDirectories(dirs paths.PathList) []error { var merr []error From 2b455310fb33dc51805c4b633963224402285b78 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 29 Mar 2022 16:34:01 +0200 Subject: [PATCH 5/6] Added cores.InstallPlatformInDirectory(..) helper function --- arduino/cores/packagemanager/install_uninstall.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arduino/cores/packagemanager/install_uninstall.go b/arduino/cores/packagemanager/install_uninstall.go index 7f527bc1fb0..17ed7ca7f98 100644 --- a/arduino/cores/packagemanager/install_uninstall.go +++ b/arduino/cores/packagemanager/install_uninstall.go @@ -23,6 +23,7 @@ import ( "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/cores/packageindex" "github.com/arduino/arduino-cli/executils" + "github.com/arduino/go-paths-helper" "github.com/pkg/errors" ) @@ -33,6 +34,11 @@ func (pm *PackageManager) InstallPlatform(platformRelease *cores.PlatformRelease "hardware", platformRelease.Platform.Architecture, platformRelease.Version.String()) + return pm.InstallPlatformInDirectory(platformRelease, destDir) +} + +// InstallPlatformInDirectory installs a specific release of a platform in a specific directory. +func (pm *PackageManager) InstallPlatformInDirectory(platformRelease *cores.PlatformRelease, destDir *paths.Path) error { if err := platformRelease.Resource.Install(pm.DownloadDir, pm.TempDir, destDir); err != nil { return errors.Errorf(tr("installing platform %[1]s: %[2]s"), platformRelease, err) } From a7803b8731ce94cd9bd5f6917cc03658413e4d6e Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 8 Mar 2022 13:16:07 +0100 Subject: [PATCH 6/6] legacy: allow using a preconfigured library manager in build --- legacy/builder/libraries_loader.go | 74 +++++++++++++++--------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/legacy/builder/libraries_loader.go b/legacy/builder/libraries_loader.go index 97ca9339c1c..4d5f0c8d5ca 100644 --- a/legacy/builder/libraries_loader.go +++ b/legacy/builder/libraries_loader.go @@ -26,51 +26,53 @@ import ( type LibrariesLoader struct{} func (s *LibrariesLoader) Run(ctx *types.Context) error { - lm := librariesmanager.NewLibraryManager(nil, nil) - ctx.LibrariesManager = lm + if ctx.LibrariesManager == nil { + lm := librariesmanager.NewLibraryManager(nil, nil) + ctx.LibrariesManager = lm - builtInLibrariesFolders := ctx.BuiltInLibrariesDirs - if err := builtInLibrariesFolders.ToAbs(); err != nil { - return errors.WithStack(err) - } - for _, folder := range builtInLibrariesFolders { - lm.AddLibrariesDir(folder, libraries.IDEBuiltIn) - } + builtInLibrariesFolders := ctx.BuiltInLibrariesDirs + if err := builtInLibrariesFolders.ToAbs(); err != nil { + return errors.WithStack(err) + } + for _, folder := range builtInLibrariesFolders { + lm.AddLibrariesDir(folder, libraries.IDEBuiltIn) + } - actualPlatform := ctx.ActualPlatform - platform := ctx.TargetPlatform - if actualPlatform != platform { - lm.AddPlatformReleaseLibrariesDir(actualPlatform, libraries.ReferencedPlatformBuiltIn) - } - lm.AddPlatformReleaseLibrariesDir(platform, libraries.PlatformBuiltIn) + actualPlatform := ctx.ActualPlatform + platform := ctx.TargetPlatform + if actualPlatform != platform { + lm.AddPlatformReleaseLibrariesDir(actualPlatform, libraries.ReferencedPlatformBuiltIn) + } + lm.AddPlatformReleaseLibrariesDir(platform, libraries.PlatformBuiltIn) - librariesFolders := ctx.OtherLibrariesDirs - if err := librariesFolders.ToAbs(); err != nil { - return errors.WithStack(err) - } - for _, folder := range librariesFolders { - lm.AddLibrariesDir(folder, libraries.User) - } + librariesFolders := ctx.OtherLibrariesDirs + if err := librariesFolders.ToAbs(); err != nil { + return errors.WithStack(err) + } + for _, folder := range librariesFolders { + lm.AddLibrariesDir(folder, libraries.User) + } - if errs := lm.RescanLibraries(); len(errs) > 0 { - // With the refactoring of the initialization step of the CLI we changed how - // errors are returned when loading platforms and libraries, that meant returning a list of - // errors instead of a single one to enhance the experience for the user. - // I have no intention right now to start a refactoring of the legacy package too, so - // here's this shitty solution for now. - // When we're gonna refactor the legacy package this will be gone. - return errors.WithStack(errs[0].Err()) - } + if errs := lm.RescanLibraries(); len(errs) > 0 { + // With the refactoring of the initialization step of the CLI we changed how + // errors are returned when loading platforms and libraries, that meant returning a list of + // errors instead of a single one to enhance the experience for the user. + // I have no intention right now to start a refactoring of the legacy package too, so + // here's this shitty solution for now. + // When we're gonna refactor the legacy package this will be gone. + return errors.WithStack(errs[0].Err()) + } - for _, dir := range ctx.LibraryDirs { - // Libraries specified this way have top priority - if err := lm.LoadLibraryFromDir(dir, libraries.Unmanaged); err != nil { - return err + for _, dir := range ctx.LibraryDirs { + // Libraries specified this way have top priority + if err := lm.LoadLibraryFromDir(dir, libraries.Unmanaged); err != nil { + return err + } } } resolver := librariesresolver.NewCppResolver() - if err := resolver.ScanFromLibrariesManager(lm); err != nil { + if err := resolver.ScanFromLibrariesManager(ctx.LibrariesManager); err != nil { return errors.WithStack(err) } ctx.LibrariesResolver = resolver