Skip to content

Commit

Permalink
gRPC: allow cancellation of downloads
Browse files Browse the repository at this point in the history
  • Loading branch information
cmaglie committed May 21, 2024
1 parent ba19a2d commit 66a4f27
Show file tree
Hide file tree
Showing 16 changed files with 44 additions and 41 deletions.
2 changes: 1 addition & 1 deletion .licenses/go/go.bug.st/downloader/v2.dep.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: go.bug.st/downloader/v2
version: v2.1.1
version: v2.2.0
type: go
summary:
homepage: https://pkg.go.dev/go.bug.st/downloader/v2
Expand Down
8 changes: 4 additions & 4 deletions commands/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ import (
"google.golang.org/grpc/status"
)

func installTool(pm *packagemanager.PackageManager, tool *cores.ToolRelease, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error {
func installTool(ctx context.Context, pm *packagemanager.PackageManager, tool *cores.ToolRelease, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error {
pme, release := pm.NewExplorer()
defer release()

taskCB(&rpc.TaskProgress{Name: tr("Downloading missing tool %s", tool)})
if err := pme.DownloadToolRelease(tool, downloadCB); err != nil {
if err := pme.DownloadToolRelease(ctx, tool, downloadCB); err != nil {
return fmt.Errorf(tr("downloading %[1]s tool: %[2]s"), tool, err)
}
taskCB(&rpc.TaskProgress{Completed: true})
Expand Down Expand Up @@ -283,7 +283,7 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor
// Install builtin tools if necessary
if len(builtinToolsToInstall) > 0 {
for _, toolRelease := range builtinToolsToInstall {
if err := installTool(pmb.Build(), toolRelease, downloadCallback, taskCallback); err != nil {
if err := installTool(ctx, pmb.Build(), toolRelease, downloadCallback, taskCallback); err != nil {
e := &cmderrors.InitFailedError{
Code: codes.Internal,
Cause: err,
Expand Down Expand Up @@ -385,7 +385,7 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor
responseError(e.GRPCStatus())
continue
}
if err := libRelease.Resource.Download(pme.DownloadDir, config, libRelease.String(), downloadCallback, ""); err != nil {
if err := libRelease.Resource.Download(ctx, pme.DownloadDir, config, libRelease.String(), downloadCallback, ""); err != nil {
taskCallback(&rpc.TaskProgress{Name: tr("Error downloading library %s", libraryRef)})
e := &cmderrors.FailedLibraryInstallError{Cause: err}
responseError(e.GRPCStatus())
Expand Down
5 changes: 2 additions & 3 deletions commands/service_library_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,15 @@ func (s *arduinoCoreServerImpl) LibraryDownload(req *rpc.LibraryDownloadRequest,
})
}

func downloadLibrary(_ context.Context, downloadsDir *paths.Path, libRelease *librariesindex.Release,
func downloadLibrary(ctx context.Context, downloadsDir *paths.Path, libRelease *librariesindex.Release,
downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB, queryParameter string, settings *configuration.Settings) error {

taskCB(&rpc.TaskProgress{Name: tr("Downloading %s", libRelease)})
config, err := settings.DownloaderConfig()
if err != nil {
return &cmderrors.FailedDownloadError{Message: tr("Can't download library"), Cause: err}
}
// TODO: Pass context
if err := libRelease.Resource.Download(downloadsDir, config, libRelease.String(), downloadCB, queryParameter); err != nil {
if err := libRelease.Resource.Download(ctx, downloadsDir, config, libRelease.String(), downloadCB, queryParameter); err != nil {
return &cmderrors.FailedDownloadError{Message: tr("Can't download library"), Cause: err}
}
taskCB(&rpc.TaskProgress{Completed: true})
Expand Down
8 changes: 3 additions & 5 deletions commands/service_platform_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func PlatformDownloadStreamResponseToCallbackFunction(ctx context.Context, downl

// PlatformDownload downloads a platform package
func (s *arduinoCoreServerImpl) PlatformDownload(req *rpc.PlatformDownloadRequest, stream rpc.ArduinoCoreService_PlatformDownloadServer) error {
ctx := stream.Context()
syncSend := NewSynchronizedSend(stream.Send)

pme, release, err := instances.GetPackageManagerExplorer(req.GetInstance())
Expand Down Expand Up @@ -71,15 +72,12 @@ func (s *arduinoCoreServerImpl) PlatformDownload(req *rpc.PlatformDownloadReques
})
}

// TODO: pass context
// ctx := stream.Context()
if err := pme.DownloadPlatformRelease(platform, downloadCB); err != nil {
if err := pme.DownloadPlatformRelease(ctx, platform, downloadCB); err != nil {
return err
}

for _, tool := range tools {
// TODO: pass context
if err := pme.DownloadToolRelease(tool, downloadCB); err != nil {
if err := pme.DownloadToolRelease(ctx, tool, downloadCB); err != nil {
return err
}
}
Expand Down
3 changes: 1 addition & 2 deletions commands/service_platform_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ func (s *arduinoCoreServerImpl) PlatformInstall(req *rpc.PlatformInstallRequest,
}
}

// TODO: Pass context
if err := pme.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, req.GetSkipPostInstall(), req.GetSkipPreUninstall()); err != nil {
if err := pme.DownloadAndInstallPlatformAndTools(ctx, platformRelease, tools, downloadCB, taskCB, req.GetSkipPostInstall(), req.GetSkipPreUninstall()); err != nil {
return err
}

Expand Down
2 changes: 1 addition & 1 deletion commands/service_platform_upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (s *arduinoCoreServerImpl) PlatformUpgrade(req *rpc.PlatformUpgradeRequest,
Package: req.GetPlatformPackage(),
PlatformArchitecture: req.GetArchitecture(),
}
platform, err := pme.DownloadAndInstallPlatformUpgrades(ref, downloadCB, taskCB, req.GetSkipPostInstall(), req.GetSkipPreUninstall())
platform, err := pme.DownloadAndInstallPlatformUpgrades(ctx, ref, downloadCB, taskCB, req.GetSkipPostInstall(), req.GetSkipPreUninstall())
if err != nil {
return platform, err
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ require (
github.com/stretchr/testify v1.9.0
github.com/xeipuuv/gojsonschema v1.2.0
go.bug.st/cleanup v1.0.0
go.bug.st/downloader/v2 v2.1.1
go.bug.st/downloader/v2 v2.2.0
go.bug.st/relaxed-semver v0.12.0
go.bug.st/testifyjson v1.1.1
golang.org/x/term v0.20.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,8 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
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/downloader/v2 v2.2.0 h1:Y0jSuDISNhrzePkrAWqz9xUC3xol9hqZo/+tz1D4EqY=
go.bug.st/downloader/v2 v2.2.0/go.mod h1:VZW2V1iGKV8rJL2ZEGIDzzBeKowYv34AedJz13RzVII=
go.bug.st/relaxed-semver v0.12.0 h1:se8v3lTdAAFp68+/RS/0Y/nFdnpdzkP5ICY04SPau4E=
go.bug.st/relaxed-semver v0.12.0/go.mod h1:Cpcbiig6Omwlq6bS7i3MQWiqS7W7HDd8CAnZFC40Cl0=
go.bug.st/serial v1.6.1 h1:VSSWmUxlj1T/YlRo2J104Zv3wJFrjHIl/T3NeruWAHY=
Expand Down
9 changes: 5 additions & 4 deletions internal/arduino/cores/packagemanager/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package packagemanager

import (
"context"
"errors"
"fmt"

Expand Down Expand Up @@ -119,21 +120,21 @@ func (pme *Explorer) FindPlatformReleaseDependencies(item *PlatformReference) (*

// DownloadToolRelease downloads a ToolRelease. If the tool is already downloaded a nil Downloader
// is returned. Uses the given downloader configuration for download, or the default config if nil.
func (pme *Explorer) DownloadToolRelease(tool *cores.ToolRelease, progressCB rpc.DownloadProgressCB) error {
func (pme *Explorer) DownloadToolRelease(ctx context.Context, tool *cores.ToolRelease, progressCB rpc.DownloadProgressCB) error {
resource := tool.GetCompatibleFlavour()
if resource == nil {
return &cmderrors.FailedDownloadError{
Message: tr("Error downloading tool %s", tool),
Cause: errors.New(tr("no versions available for the current OS, try contacting %s", tool.Tool.Package.Email))}
}
return resource.Download(pme.DownloadDir, pme.downloaderConfig, tool.String(), progressCB, "")
return resource.Download(ctx, pme.DownloadDir, pme.downloaderConfig, tool.String(), progressCB, "")
}

// DownloadPlatformRelease downloads a PlatformRelease. If the platform is already downloaded a
// nil Downloader is returned.
func (pme *Explorer) DownloadPlatformRelease(platform *cores.PlatformRelease, progressCB rpc.DownloadProgressCB) error {
func (pme *Explorer) DownloadPlatformRelease(ctx context.Context, platform *cores.PlatformRelease, progressCB rpc.DownloadProgressCB) error {
if platform.Resource == nil {
return &cmderrors.PlatformNotFoundError{Platform: platform.String()}
}
return platform.Resource.Download(pme.DownloadDir, pme.downloaderConfig, platform.String(), progressCB, "")
return platform.Resource.Download(ctx, pme.DownloadDir, pme.downloaderConfig, platform.String(), progressCB, "")
}
9 changes: 6 additions & 3 deletions internal/arduino/cores/packagemanager/install_uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package packagemanager

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
Expand All @@ -33,6 +34,7 @@ import (
// This method takes care of downloading missing archives, upgrading platforms and tools, and
// removing the previously installed platform/tools that are no longer needed after the upgrade.
func (pme *Explorer) DownloadAndInstallPlatformUpgrades(
ctx context.Context,
platformRef *PlatformReference,
downloadCB rpc.DownloadProgressCB,
taskCB rpc.TaskProgressCB,
Expand Down Expand Up @@ -62,7 +64,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades(
if err != nil {
return nil, &cmderrors.PlatformNotFoundError{Platform: platformRef.String()}
}
if err := pme.DownloadAndInstallPlatformAndTools(platformRelease, tools, downloadCB, taskCB, skipPostInstall, skipPreUninstall); err != nil {
if err := pme.DownloadAndInstallPlatformAndTools(ctx, platformRelease, tools, downloadCB, taskCB, skipPostInstall, skipPreUninstall); err != nil {
return nil, err
}

Expand All @@ -73,6 +75,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades(
// This method takes care of downloading missing archives, installing/upgrading platforms and tools, and
// removing the previously installed platform/tools that are no longer needed after the upgrade.
func (pme *Explorer) DownloadAndInstallPlatformAndTools(
ctx context.Context,
platformRelease *cores.PlatformRelease, requiredTools []*cores.ToolRelease,
downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB,
skipPostInstall bool, skipPreUninstall bool) error {
Expand All @@ -92,11 +95,11 @@ func (pme *Explorer) DownloadAndInstallPlatformAndTools(
// Package download
taskCB(&rpc.TaskProgress{Name: tr("Downloading packages")})
for _, tool := range toolsToInstall {
if err := pme.DownloadToolRelease(tool, downloadCB); err != nil {
if err := pme.DownloadToolRelease(ctx, tool, downloadCB); err != nil {
return err
}
}
if err := pme.DownloadPlatformRelease(platformRelease, downloadCB); err != nil {
if err := pme.DownloadPlatformRelease(ctx, platformRelease, downloadCB); err != nil {
return err
}
taskCB(&rpc.TaskProgress{Completed: true})
Expand Down
12 changes: 6 additions & 6 deletions internal/arduino/cores/packagemanager/profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (pmb *Builder) LoadHardwareForProfile(ctx context.Context, p *sketch.Profil

for _, toolDep := range platformRelease.ToolDependencies {
indexURL := indexURLs[toolDep.ToolPackager]
if err := pmb.loadProfileTool(toolDep, indexURL, installMissing, downloadCB, taskCB, settings); err != nil {
if err := pmb.loadProfileTool(ctx, toolDep, indexURL, installMissing, downloadCB, taskCB, settings); err != nil {
merr = append(merr, fmt.Errorf("%s: %w", tr("loading required tool %s", toolDep), err))
logrus.WithField("tool", toolDep).WithField("index_url", indexURL).WithError(err).Debugf("Error loading tool for profile")
} else {
Expand Down Expand Up @@ -122,7 +122,7 @@ func (pmb *Builder) installMissingProfilePlatform(ctx context.Context, platformR
tmpPme, tmpRelease := tmpPm.NewExplorer()
defer tmpRelease()

if err := tmpPme.DownloadPlatformRelease(tmpPlatformRelease, downloadCB); err != nil {
if err := tmpPme.DownloadPlatformRelease(ctx, tmpPlatformRelease, downloadCB); err != nil {
taskCB(&rpc.TaskProgress{Name: tr("Error downloading platform %s", tmpPlatformRelease)})
return &cmderrors.FailedInstallError{Message: tr("Error downloading platform %s", tmpPlatformRelease), Cause: err}
}
Expand All @@ -138,7 +138,7 @@ func (pmb *Builder) installMissingProfilePlatform(ctx context.Context, platformR
return nil
}

func (pmb *Builder) loadProfileTool(toolRef *cores.ToolDependency, indexURL *url.URL, installMissing bool, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB, settings *configuration.Settings) error {
func (pmb *Builder) loadProfileTool(ctx context.Context, toolRef *cores.ToolDependency, indexURL *url.URL, installMissing bool, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB, settings *configuration.Settings) error {
targetPackage := pmb.packages.GetOrCreatePackage(toolRef.ToolPackager)
tool := targetPackage.GetOrCreateTool(toolRef.ToolName)

Expand All @@ -151,15 +151,15 @@ func (pmb *Builder) loadProfileTool(toolRef *cores.ToolDependency, indexURL *url
if toolRelease == nil {
return &cmderrors.InvalidVersionError{Cause: fmt.Errorf(tr("version %s not found", toolRef.ToolVersion))}
}
if err := pmb.installMissingProfileTool(toolRelease, destDir, downloadCB, taskCB); err != nil {
if err := pmb.installMissingProfileTool(ctx, toolRelease, destDir, downloadCB, taskCB); err != nil {
return err
}
}

return pmb.loadToolReleaseFromDirectory(tool, toolRef.ToolVersion, destDir)
}

func (pmb *Builder) installMissingProfileTool(toolRelease *cores.ToolRelease, destDir *paths.Path, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error {
func (pmb *Builder) installMissingProfileTool(ctx context.Context, toolRelease *cores.ToolRelease, destDir *paths.Path, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error {
// Instantiate a temporary package manager only for platform installation
tmp, err := paths.MkTempDir(destDir.Parent().String(), "")
if err != nil {
Expand All @@ -173,7 +173,7 @@ func (pmb *Builder) installMissingProfileTool(toolRelease *cores.ToolRelease, de
return &cmderrors.InvalidVersionError{Cause: fmt.Errorf(tr("version %s not available for this operating system", toolRelease))}
}
taskCB(&rpc.TaskProgress{Name: tr("Downloading tool %s", toolRelease)})
if err := toolResource.Download(pmb.DownloadDir, pmb.downloaderConfig, toolRelease.String(), downloadCB, ""); err != nil {
if err := toolResource.Download(ctx, pmb.DownloadDir, pmb.downloaderConfig, toolRelease.String(), downloadCB, ""); err != nil {
taskCB(&rpc.TaskProgress{Name: tr("Error downloading tool %s", toolRelease)})
return &cmderrors.FailedInstallError{Message: tr("Error installing tool %s", toolRelease), Cause: err}
}
Expand Down
5 changes: 3 additions & 2 deletions internal/arduino/httpclient/httpclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package httpclient

import (
"context"
"time"

"github.com/arduino/arduino-cli/commands/cmderrors"
Expand All @@ -31,7 +32,7 @@ var tr = i18n.Tr
// DownloadFile downloads a file from a URL into the specified path. An optional config and options may be passed (or nil to use the defaults).
// A DownloadProgressCB callback function must be passed to monitor download progress.
// If a not empty queryParameter is passed, it is appended to the URL for analysis purposes.
func DownloadFile(path *paths.Path, URL string, queryParameter string, label string, downloadCB rpc.DownloadProgressCB, config downloader.Config, options ...downloader.DownloadOptions) (returnedError error) {
func DownloadFile(ctx context.Context, path *paths.Path, URL string, queryParameter string, label string, downloadCB rpc.DownloadProgressCB, config downloader.Config, options ...downloader.DownloadOptions) (returnedError error) {
if queryParameter != "" {
URL = URL + "?query=" + queryParameter
}
Expand All @@ -45,7 +46,7 @@ func DownloadFile(path *paths.Path, URL string, queryParameter string, label str
}
}()

d, err := downloader.DownloadWithConfig(path.String(), URL, config, options...)
d, err := downloader.DownloadWithConfigAndContext(ctx, path.String(), URL, config, options...)
if err != nil {
return err
}
Expand Down
5 changes: 3 additions & 2 deletions internal/arduino/resources/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package resources

import (
"context"
"fmt"
"os"

Expand All @@ -28,7 +29,7 @@ import (
// Download performs a download loop using the provided downloader.Config.
// Messages are passed back to the DownloadProgressCB using label as text for the File field.
// queryParameter is passed for analysis purposes.
func (r *DownloadResource) Download(downloadDir *paths.Path, config downloader.Config, label string, downloadCB rpc.DownloadProgressCB, queryParameter string) error {
func (r *DownloadResource) Download(ctx context.Context, downloadDir *paths.Path, config downloader.Config, label string, downloadCB rpc.DownloadProgressCB, queryParameter string) error {
path, err := r.ArchivePath(downloadDir)
if err != nil {
return fmt.Errorf(tr("getting archive path: %s"), err)
Expand All @@ -52,5 +53,5 @@ func (r *DownloadResource) Download(downloadDir *paths.Path, config downloader.C
} else {
return fmt.Errorf(tr("getting archive file info: %s"), err)
}
return httpclient.DownloadFile(path, r.URL, queryParameter, label, downloadCB, config)
return httpclient.DownloadFile(ctx, path, r.URL, queryParameter, label, downloadCB, config)
}
3 changes: 2 additions & 1 deletion internal/arduino/resources/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package resources

import (
"context"
"net/http"
"net/http/httptest"
"os"
Expand Down Expand Up @@ -56,7 +57,7 @@ func TestDownloadApplyUserAgentHeaderUsingConfig(t *testing.T) {
settings.Set("network.user_agent_ext", goldUserAgentValue)
config, err := settings.DownloaderConfig()
require.NoError(t, err)
err = r.Download(tmp, config, "", func(progress *rpc.DownloadProgress) {}, "")
err = r.Download(context.Background(), tmp, config, "", func(progress *rpc.DownloadProgress) {}, "")
require.NoError(t, err)

// leverage the download helper to download the echo for the request made by the downloader itself
Expand Down
4 changes: 2 additions & 2 deletions internal/arduino/resources/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (res *IndexResource) Download(ctx context.Context, destDir *paths.Path, dow
return err
}
tmpIndexPath := tmp.Join(downloadFileName)
if err := httpclient.DownloadFile(tmpIndexPath, res.URL.String(), "", tr("Downloading index: %s", downloadFileName), downloadCB, config, downloader.NoResume); err != nil {
if err := httpclient.DownloadFile(ctx, tmpIndexPath, res.URL.String(), "", tr("Downloading index: %s", downloadFileName), downloadCB, config, downloader.NoResume); err != nil {
return &cmderrors.FailedDownloadError{Message: tr("Error downloading index '%s'", res.URL), Cause: err}
}

Expand Down Expand Up @@ -133,7 +133,7 @@ func (res *IndexResource) Download(ctx context.Context, destDir *paths.Path, dow
// Download signature
signaturePath = destDir.Join(signatureFileName)
tmpSignaturePath = tmp.Join(signatureFileName)
if err := httpclient.DownloadFile(tmpSignaturePath, res.SignatureURL.String(), "", tr("Downloading index signature: %s", signatureFileName), downloadCB, config, downloader.NoResume); err != nil {
if err := httpclient.DownloadFile(ctx, tmpSignaturePath, res.SignatureURL.String(), "", tr("Downloading index signature: %s", signatureFileName), downloadCB, config, downloader.NoResume); err != nil {
return &cmderrors.FailedDownloadError{Message: tr("Error downloading index signature '%s'", res.SignatureURL), Cause: err}
}

Expand Down
4 changes: 2 additions & 2 deletions internal/arduino/resources/resources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func TestDownloadAndChecksums(t *testing.T) {
require.NoError(t, err)

downloadAndTestChecksum := func() {
err := r.Download(tmp, downloader.Config{}, "", func(*rpc.DownloadProgress) {}, "")
err := r.Download(context.Background(), tmp, downloader.Config{}, "", func(*rpc.DownloadProgress) {}, "")
require.NoError(t, err)

data, err := testFile.ReadFile()
Expand All @@ -64,7 +64,7 @@ func TestDownloadAndChecksums(t *testing.T) {
downloadAndTestChecksum()

// Download with cached file
err = r.Download(tmp, downloader.Config{}, "", func(*rpc.DownloadProgress) {}, "")
err = r.Download(context.Background(), tmp, downloader.Config{}, "", func(*rpc.DownloadProgress) {}, "")
require.NoError(t, err)

// Download if cached file has data in excess (redownload)
Expand Down

0 comments on commit 66a4f27

Please sign in to comment.